Forwarding a port on public interface into tor

I need co accomplish a specific task - to forward a single port from public interface to a tor hidden service.
The whonix box should act as a fake server. Any incoming requests to this port should be forwarded to tor hidden service, and the responses should be forwarded back to client. Without tor involved this would be a simple NAT relation, I think
What I have now:
Whonix Gateway (WG) with private (eth1) interface and public (eth0) interface say
I don’t actually need the eth1 for my task, but left it by now to play around.
The hidden service is up and running on separate host. On WG it is statically mapped as
I can successfully connect to the service by IP from WG, WW and any workstation on subnet (WG acts as gateway).
If was real public address with no Tor involved I suppose following would work:
iptables -t nat -I PREROUTING 1 -p tcp --dport 80 -j DNAT --to-destination
iptables -t nat -I POSTROUTING 1 -j MASQUERADE
But it doesn’t. I’m unable to connect to from any interface or locally at WG.
I tried lots of combinations, added more INPUT and OUTPUT rules etc., nothing helps. I think I lack some fundamental knowledge to understand what’s wrong.
I’d appreciate any help. Thanks.

You do realize that this would not be anonymous?

Are you sure the standard guide on how to set up Tor hidden services would not suffice?

What do you mean by fake server?

What should this be useful for?

Since this sounds rather difficult… Did you figure out how to set this up without Whonix being involved first? I highly recommend a case study if this is doable at all until you try to modify Whonix to make that work also.

The Whonix specific stuff… Basically:

  1. add extra rule to Whonix firewall (since we have no config option to open arbitrary incoming ports) (You can add it similar to the above, but outside (!) the if.

For example in /usr/bin/whonix_firewall… Below this line (but outside the if):

$iptables_cmd -A INPUT -i "$ext_if_item" -p tcp --dport 22 -j ACCEPT
  1. You also need a - virtualizer specific [Which virtualizer?] - way to open that port in the virtualizer.

similar to:

I think yes. My goal is to hide actual hidden service location only, I’m not going to hide tha fact of using WG. The hidden service is actually a VPN server (my own). By this setup I hope to acive

  • easy client setup - a simple vpn client only
  • protection against mitm on tor exit node
  • no revealing of hidden service location

Yes. I actually have the hidden serevice running already. Everything works from the private subnet Written above). The problem is - I’ll have no private subnet in “production” environment

The WG box should behave as a VPN server. In fact it’ll be not a server, but establish a secure channel to actual server, hidden within tor.

Actually not. I ony studied the Internet and it seems a kind of standart task, not too difficult. You’re right, I need to tast that setup without tor

This is about allowing incoming ssh. I already did it (by enabling the corresponding option in firewall setup). How could it relate to my problem? I you mean opening MY needed port in the same way - I also tried a similar INPUT rule, it didn’t help.
My setup (4 hosts: 2 in private and 2 in public subnet) runns in virtual lab by now, I uctually didn’t open anything on the hypervisor host.

Oops. I meant to imply “without Whonix but with Tor”. However, starting even simpler without involving Tor is even better. This seems a good way to experiment this step by step:

  1. no Tor
  2. Tor
  3. Whonix with Tor

It’s just an example how to open an external port in Whonix-Gateway. With minor tweaks you can turn this from “open ssh port” to “open an arbitrary port”.

Yes, I already got what you mean. I tried this with my port, but it didn’t help. The problem lays somewhere else I guess…

Ok, I spent several days studying debian and iptables (i’m actually a guy from M$ world, half of this time has been wasted to solve simple things like making ssh and sudo/kde work, getting used to nano etc.)
I finally found a solution (below), still not tested on whonix, but worth reporting.

Stage 1.
For middlebox I deployed a clean Debian Jessie with single network interface eth0 (for this example).
The destination web server is with Apache responding on port 80. The default web page displays the client IP.
Client machine - regular Win workstation somewhere on external network.
Goal: request the web page from middlebox and get proper answer served by webserver.
Following script made this possible:

Config 1: No Whonix, No Tor, No hidden service
sysctl -w net.ipv4.ip_forward=1
iptables -F
iptables -F -t nat
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
iptables -A PREROUTING -t nat -p tcp --dport $localPort -j DNAT --to-destination $destAddr:$destPort
iptables -A FORWARD -p tcp --dport $destPort -d $destAddr -j ACCEPT
iptables -A POSTROUTING -t nat -j MASQUERADE
iptables -A FORWARD -p tcp --sport $destPort -s $destAddr -j ACCEPT

#the lines below just to let system work with tight default policy
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth0 -p udp --dport 53 -j ACCEPT
iptables -A INPUT -i eth0 -p udp --sport 53 -j ACCEPT

When requesting URL http:// from webserver by client machine (regular CHROME browser), the page is returned displaying client address equal to client mchine IP. When requesting middlebox URL http:// , the page also loads ok, but displays client IP, that means that middlebox successfully redirected my request to webserver and forwarded the response back to client machine. Goal reached.

Stage 2:
Intalled Tor on both middlebox and webserver .
On webserver set up a hidden web service with name abcdef.onion , checked proper operation via client machine Tor Browser. The page displays client IP (the decrypted request appears to originate from webserver’s local tor router)
On middlebox added following to /etc/tor/torrc:
TransPort 9040
DNSPort 53
MapAddress abcdef.onion
Then rewrote iptables script using this Tutorial
Changed default policies to ACCEPT and ended up with following script:

Config 2: No Whonix, No hidden service, trying to torify all traffic
sysctl -w net.ipv4.ip_forward=1
iptables -F
iptables -F -t nat
iptables -F -t raw
iptables -P INPUT ACCEPT

#the UID that Tor runs as (varies from system to system)
#Tor's TransPort

### for debugging only
iptables -t raw -A PREROUTING -p tcp -m multiport --dports 80,8888,9040 -j TRACE
iptables -t raw -A PREROUTING -p tcp -m multiport --sports 80,8888,9040 -j TRACE
iptables -t raw -A OUTPUT -p tcp -m multiport --sports 80,8888,9040 -j TRACE
iptables -t raw -A OUTPUT -p tcp -m multiport --dports 80,8888,9040 -j TRACE

### torify requests from local system
iptables -t nat -A OUTPUT -o lo -j RETURN
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $_trans_port

### torify routed requests
iptables -t nat -A PREROUTING -p tcp --dport $localPort -j DNAT --to-destination $destAddr:$destPort
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A PREROUTING -p tcp --syn -j REDIRECT --to-ports $_trans_port

iptables -A POSTROUTING -t nat -j MASQUERADE

With this script I got strange results.
When making http request from inside middlebox (“curl”) the page returns successfully displaying client IP from Tor network. That means that locally-originated requests are torified correctly.
But when making request http:// from client machine, the page returns client IP , the forwarding works ok as in stage 1, but not torified.
Obviously , the rule
iptables -t nat -A PREROUTING -p tcp --dport $localPort -j DNAT --to-destination $destAddr:$destPort
works in this case, but
iptables -t nat -A PREROUTING -p tcp --syn -j REDIRECT --to-ports $_trans_port
does not.
On various iptables manuals over Inet I never saw that DNAT or REDIRECT actions stop chain traversal.
The situation above (as long as examining the TRACE output) shows, that after the first rule is matched in the PREROUTING chain, the processing of other rules in this chain stops, and never reaches the third REDIRECT . Since the destination address is DNATed to external webserver IP, a “routing decision” is made and the packet goes through FORWARD chains and is fired outside. No chance to get torified.
By now I have no idea how to make the packet to be processed by both rules (DNAT and REDIRECT). And no other table or chain allows DNAT or REDIRECT for incoming packets.

Nevertheless, the solution was found, not completely the iptables-way
Stage 3:
Luckily I stumbled across redir
This is a software port forwarder. It can be used instead of kernel/netfilter NAT facility.
The main difference is that the forwarded packets generated by it are treated by local system as locally-originated, thus these packets are processed by OUTPUT chain instead of FORWARD. And output chain allows us to make REDIRECT to Tor TransPort (see above rules).
Since we don’t need kernel packet forwarding anymore, we can disable it.
Final rewritten script looks like following:

Config 3: No Whonix, trying to torify all traffic, trying hidden service
sysctl -w net.ipv4.ip_forward=0
iptables -F
iptables -F -t nat
iptables -F -t raw
iptables -P INPUT ACCEPT

#the UID that Tor runs as (varies from system to system)
#Tor's TransPort

### torify requests from local system
iptables -t nat -A OUTPUT -o lo -j RETURN
iptables -t nat -A OUTPUT -m owner --uid-owner $_tor_uid -j RETURN
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $_trans_port

Then I launched
redir --lport=80 --dport=80 --caddr=
to forward all incoming requests on port 80 to the hidden service mapped IP. The rest does tor.
After all I’m able to request http:// by client machine, and get result wpage displaying client IP . The goal is reached, My request to middlebox gets into tor network, reaches hidden service and the response finds it’s way back.
If it was VPN server instead of Apache, I’d get a transparent secure channel from client machine to remote VPN server, immune to MITM, and not even knowing VPN server location. The server would also not know my address (not critical).
Now I’ll try to apply everything above to Whonix.

1 Like

Thanks for clear, detailed write-up. Hoping to learn from your progress.

From man iptables-extensions:

DNAT: This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only called from those chains. It specifies that the destination address of the packet should be modified (and all future packets in this connection will also be mangled), and rules should cease being examined.

I can understand the motivation for wanting to isolate a webserver from the Tor Gateway. Are you also uncomfortable with having a hidden server on the openvpn server itself? Or is there another reason that a separate gateway is needed to serve the openvpn server?

Did you see this already? https://www.whonix.org/wiki/OnionCat

The openvpn server WILL BE the hidden service. The experiments above used web server instead of vpn server because web server is easier to setup and query (and helps quickly determine client ip). In “production” I’ll have openvpn server published as hidden service, other user demanded services (maybe web mail or file sharing or remote desktop) will be available through vpn tunnel’s virtual subnet (default subnet is 10.8..).
But vpn client can’t connect to vpn server by .onion name, that’s the main motivation for setting up a common middlebox. Otherwise I should provide separate whonix infrastructure for each client.
When my setup is finished, I’ll get clear benefits:

  1. First of all, the destination server’s location remains hidden, even in case the middlebox or a client is compromised. (The server will reside behind a strict firewall and have no access to Internet besides openvpn tunnel)
  2. Second, the client setup get very easy - only a simple openvpn installation, all clients connect to the same middlebox by single public IP.
  3. Clients or any observer on clients side don’t know anything about tor involved, that’s far less suspicious than using tor
  4. The tunnel is encrypted end-to-end, there is no unencrypted segment (comparing to other tor/vpn scenarios), eavesdropping is impossible even by malcious tor nodes or compromised middlebox (I guess).
  5. Multiple middleboxes can be used for different client groups, each group works with it’s own middlebox revealing no correlation with other groups.
  6. In case of emergency the middlebox can be shutdown or even wiped out remotely, “burning the bridge” to hidden server. Also the redirection can be switched to a decoy server.
  7. Since clients, middlebox and hidden server are supposed to be physically located in different countries, timing attacks seem to be impossible.
    The main problem personally for me remains deploying Whonix middlebox somewhere on VPS. The docs say it’s neither easy nor recommended. Instead I could setup a clean Debian installation from scratch as I did above, but I find Whonix to be far more secure and admin-friendly and highly appreciate creator’s efforts.
    Add.: Another problem is possible low througput or high latency. Need to test it when final setup is complete.

No. I’m not sure If it can help me, but I definitely will check this out. I really hope not to have wasted several days inventing the wheel :wink:

Examined OnionCat docs (didn;t try to install).
Yes it’s very close to what I wanted to achive. The drawback comparing to my scheme is more complicated client setup, including tor router running on client. Advantages are also there: anonymity of all parties, no need for middlebox.
I’ll go on finalizing my setup, It suits my needs better. I’ll also try OnionCat for different tasks, maybe for administration.

I understand now. The primary motivation of this project is to protect the destination server. Client anonymity is up to each client to implement.

  1. clients only know the public IP of the middlebox and so must use clearnet for outgoing traffic. clients are not allowed to know the server’s .onion address.
  2. client traffic is tunneled using a vpn protocol to a middlebox
  3. middlebox routes vpn traffic to vpn server over tor

In essence, what you are doing is putting a shared, remote Tor Gateway on a VPS router.

Yes, you will get clear benefits. Your clients on the other hand… Let’s hope they use Whonix to connect to the middlebox.

It’s easy and the protection is proportionate. This is borderline reckless unless you couldn’t care less about the clients. If one client is compromised, it’s safe to assume that the identities of all of the other clients using the middlebox will be compromised as well. The only way to avoid that is to have one middlebox per client.

Having clients use Whonix-Gateway in combination with a VPN achieves the same results plus provides real anonymity to your clients. You can still protect yourself by publishing your .onion in authenticated mode.

It’s only impossible if the distance between countries changes randomly.

Don’t know about difficulty but it’s safe to say that no one around here will recommend throwing clients under the bus. If Whonix is too difficult for your clients, have them use Tails / TBB.

Mmmm. Not sure I understood you right. I would better say “building private VPN tunnel through shared remote tor tunnel”

Hey, I doubt there is place for offense here.
You misunderstood the client part. “clients” are meant friendly workstations, some of them under my own control. I AM the clients and the server. Also “clients” doesn’t mean commercial stuff, they’re just “client side” in the “client-server” paradigm.
I don’t care about client anonymity the way it’s meant by the tor concept. Client anonymity from tor point of view is that:

  1. client connects to any potentially hostile server and the server shouldn’t be able to get enough info to associate the client to real person/host (geting the client IP is the easiest way to build such association, that;s why tor is mainly about hiding the source IP)
  2. client wants to use public network but prevent any third party to get info about the client or eavesdrop on transmitted data.
    My setup completely fulfills condition 1 and partially fulfills 2. It protects client data end-to-end, but doesn’t hide client’s IP. FROM WHOM? Both middlebox and server are trusted by concept, there is no problem if any observer sees a vpn tunne fro a client to middlebox without chance of eavesdropping. The only risk for the client is actually some brutal person getting physical access to client’s workstation.
    On the contrary, installing only tor on client doesn’t increase anonymity much if the client doesn’t follow anonymity rules. You certainly should know, that many people install tor thinking it to be ultimate protection and immediately reveal tons of passwords through malcious exit nodes just by not using https in login forms…
    I’m part of a team that needs a secure place for collaboration (that hidden server). Most of team members have no idea about anonymity, about routing, running virtual machines etc., they’re unable to setup anything complicated on their PC’s. Trying to deploy whonix infrastructure to each of them would be a failure. That’s why I try to go the way with common middlebox.

You better should insert [our] in this case. As I said, I’m part of a team and my goal to provide equal security to all teammates. Burning the bridge actually protects the whole team, because vital server data remains undisclosed.

I thnk you’re only partially right. Even if one client gets compromised he only gets access to server, not to other clients. Since connections to server go from tor network (, the only info an attacker could get (maybe) is the other client’s IP in the virtual subnet.

Yes, your description sounds more accurate.

My intention wasn’t to either offend or not offend. The point was to emphasize that your clients - whether they’re devices, people, customers, or you - are not receiving nearly the same level of protection as the server.

If the clients are under your control, you very clearly have the better option of using Whonix with all of your clients and connecting directly to the hidden server. Even for novice users, TBB/Tails would be far more preferable than this more complicated, less secure setup. Especially when you consider that TBB/Tails could be shipped in a hardened configuration dedicated to this sole use case.

Ahh, but you’re assuming that the only mistakes people make are InfoSec mistakes and that the only compromises people face are remotely-exploited InfoSec compromises. In reality, there are very few real-world cases of failures in InfoSec (ie cryptography, Tor protocol, etc) and every indication is that people are far more prone to be compromised by bad OpSec. Thus a good InfoSec strategy anticipates failures in OpSec and mitigates the damage that results. Consider this scenario…

You run a whistleblower website on your hidden server and a group of whistleblowers (unrelated to each other, so more anonymous than your team) wish to submit leaks by connecting to your middlebox. One of them leaves a document on the passenger seat of her car and falls under suspicion by the adversaries. This person is raided and computers are seized. The adversaries find out by examining computer that this person has been connecting to your middlebox. Obviously, it’s trivial to locate the middlebox. They seize the middlebox and grab every incoming IP address. Result: Everyone that touched the middlebox is now de-anonymized and teammates=very angry. But the server should be safe…

It’s actually worse. Unlike a public VPN used to route to Tor, your middlebox serves only one purpose and is accessed by only your client group. There is no plausible deniability - everyone is guilty by association. Adversaries don’t even need to physically access either the compromised client device or the middlebox. All they need to do are view the logs of the client & middlebox ISP’s. You would never know there was a compromise until the entire group is rounded up.

As in prior example, the middlebox can not be trusted since it is out of your physical control and easily located / compromised.

True, it doesn’t do much for the compromised client - but it means everything to the security of the middlebox and using Tor keeps the other non-compromised clients safe.

Ok, I understand your point of view now. I can agree with all you wrote above. 100%. The kind of activities you described, the risks level and (I guess) the adversary resources certainly demand anonymity level you talk about.
My situation is much simplier. There is nothing in our activities that could attract such a skilful and powerful adversary like a government agency or a criminal group or similar… That’s why I can’t even imagine IN MY CASE that somebody would bother compromising the middlebox or do complicated attacks or seize workstations etc. My teammates are no secret, we don’t hide the fact that we cooperate. If anybody would need to get list of team members, he could just observe our regular email correspondence or check smartphone address book. There is only a small part of our activities that needs to be hidden. That’s why even my setup as actually an overkill, not to speak about your described above.
Again, I completely agree with you in situation you described above, I’m completely aware of such risks. My situation is simply different.

1 Like

Obviously, you know your situation best. Just making sure you know the risks. Good luck.

[Also, the example I wrote is not so far-fetched and doesn’t require much skill from the adversary. Not that hard for even local law enforcement to obtain subpoenas in the US. And in some countries, a bottle of liquor might be all it takes…]

[Would still be interested in seeing how you manage this. Please keep this updated. Thanks!]

1 Like

I’m finally done with my setup. This is the final followup

I think here should be a disclaimer: What I’ve done is not the way whonix is meant to work and not the purpose whonix was created for. This setup violates many recommendations and brings clear anonymity risks. I doubt anybode should ever repeat this.

So, the last step was setting up the middlebox somwhere on the Net. I chose Linode KVM VPS. Mainly because they offer ability to launch a live ISO and use it to clone storage from my local VM. Unfortunately I had no success with this (the sustem didn’t boot, maybe because I did something wrong), but the VPS was already up and paid so I continued with it. So I had to install clean Debian and build Whonix from source.

I used this manual https://www.whonix.org/wiki/Dev/Build_Documentation/Physical_Isolation#How_To_Install_Whonix-Gateway_on_Hardware_.28RECOMMENDED.29

Building was successful, without a single glitch. After reboot I got a clean Whonix-Gateway, identical (I hope) to VM destribution. Then I made additional tuning to make it work as I need:

I. Because of absent eth1 Tor service failed to launch, and the control port filter failed also.
I edited etc/tor/torrc file to disable any SocksPorts bound to address. Any instruction in torrc file overrides ALL similar instructions in default config. So I added only SocksPorts and TransPort which bind to, this effectively disabled other SocksPorts.

MapAddress abcdef.onion
TransPort IsolateDestAddr IsolateDestPort
SocksPort IsolateDestAddr IsolateDestPort
# etc... from default file 

After these modifications tor service started successfully

II. To disable eth1 presence check by WhonixCheck a file should be created
with following line in it
whonixcheck_skip_functions+=" check_network_interfaces "

III. I disabled control port filter. Actually, there was no need to, because it failed anyway, I just didn’t want to observe the red “FAILED” event in system log. The instructions for disabling it are pretty clear, I had no problem with them. https://www.whonix.org/wiki/Advanced_Security_Guide#Disable_Control_Port_Filter_Proxy
a) Add line
to custom firewall config file
b) disable service by typing
sudo systemctl mask control-port-filter-proxy-python
c) disable service checking by WhonixCheck adding
whonixcheck_skip_functions+=" check_control_port_filter_running "

IV. For testing purposes I enabled SSH (mainly for SFTP access) by adding
to custom firewall config file

V. Installed redir. The problem was redir doesn’t come with a service, and is even unable to demonize itself. So I spent pretty much time to figure out how to write a service script for it.
a) apt-get install redir
b) placed a service script /etc/init.d/redir-d with following contents

# Provides:          redir-d
# Required-Start:    $local_fs $network $named $time $syslog
# Required-Stop:     $local_fs $network $named $time $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Description:       redir daemon
_OPTIONS="--cport=12345 --lport=12345 --caddr="

start() {
  start-stop-daemon --start --background --exec $_EXECUTABLE -- $_OPTIONS
  exit 0
stop() {
  start-stop-daemon --stop --exec $_EXECUTABLE --retry 5

case "$1" in
    echo "Usage: $0 {start|stop|restart}"

I realize this is definitely not the best or cleanest script ever written (error handling is completely absent) but it works for me.
c) install service by typing
update-rc.d redir-d defaults

VI. Then I had to modify firewall rules for redirection to work. I found no way to run a custom script when firewall is loaded. The main firewall script is /usr/bin/whonix_firewall . I decided not to hardcode iptables rules into it (because they could be overwritten on update), but add an ability to launch custom script.
a) added some lines near bottom of /usr/bin/whonix_firewall

## Invoke Custom Firewall Script
if [ -f "$CUSTOM_SCRIPT" ]
    source $CUSTOM_SCRIPT
## End

b) the option variables are read from /etc/whonix_firewall.d/50_user.conf, so I added my variable to it
I don’t know what is the best practice to place such scripts, maybe /home/user/ is not the best place…
The /home/user/whonix_firewall_custom script contains actual iptables rules

iptables -I INPUT 15 -p tcp --dport $localPort --syn -j ACCEPT
iptables -I OUTPUT 1 -t nat -d $destAddr -p tcp --dport $destPort --syn -j REDIRECT --to-ports $transPort

Finally I’m able to establish OpenVPN connection with this middlebox on port 12345 and land inside my hidden server. Profit.

Next I plan to drill deeper into stream isolation, because I’m not sure if each client uses the same circuit or not. I think the circuits should be separate bacause of hidden service protocol (as I understood it), but didn’t find any evidence for this yet.

And Patrick, sorry for downgrading your masterpiece. Anyway, this was a great educational possibility and big fun for me. I was a complete newbie in Linux some weeks ago, now I’m … still a complete newbie :slight_smile:

1 Like

This will improve with Whonix 14 btw, because then Whonix firewall is load through a systemd unit file so you could use an ExecStartPre / ExecStartPost systemd drop-in snippet and thereby have a post hook that will not be lost after upgrades.

(That would be doable today also by using /etc/network/pre-up.d.)

Don’t mind. :slight_smile: I am glad Whonix is useful to use. One reason it is Libre Software / Open Source is so people can hack it for their purposes.

Rocket science…

Not really.



Another hack that should already work for pre run code would be adding the commands to /etc/whonix_firewall.d/50_user.conf.

oh, thanks, I’ll try this out.

[Imprint] [Privacy Policy] [Cookie Policy] [Terms of Use] [E-Sign Consent] [DMCA] [Investors] [Priority Support] [Professional Support]