Skip to content

Instantly share code, notes, and snippets.

@Joeviocoe
Forked from daktak/qvm-exposeip.sh
Last active June 16, 2021 11:40
Show Gist options
  • Select an option

  • Save Joeviocoe/6c4dc0c283f6d6c5b1a3f5af8793292b to your computer and use it in GitHub Desktop.

Select an option

Save Joeviocoe/6c4dc0c283f6d6c5b1a3f5af8793292b to your computer and use it in GitHub Desktop.
Qubes-os port forwarding to allow external connections
#!/bin/bash
#change dev to your exposed device name
#./qvm-exposeip.sh personal 80
dev=wlp0s1
appvm=$1
port=$2
net=$3
fw=$4
if [ -z ${net} ]; then
net=sys-net
fi
if [ -z ${fw} ]; then
fw=sys-firewall
fi
externip=`qvm-run -p ${net} -u root "ifconfig ${dev}" | grep broadcast |col -x | awk '{print $2}'`
fwip=`qvm-ls -n | grep \{${fw}\} | col -x | awk '{print $14}'`
vmip=`qvm-ls -n | grep ${appvm} | col -x | awk '{print $13}'`
exenet="iptables -t nat -A PREROUTING -i ${dev} -p tcp --dport ${port} -d ${externip} -j DNAT --to-destination ${fwip} && iptables -I FORWARD 2 -i ${dev} -d ${fwip} -p tcp --dport ${port} -m conntrack --ctstate NEW -j ACCEPT"
qvm-run -p -u root ${net} "${exenet}"
exefw="iptables -t nat -A PREROUTING -i eth0 -p tcp --dport $port -d ${fwip} -j DNAT --to-destination ${vmip} && iptables -I FORWARD 2 -i eth0 -d ${vmip} -p tcp --dport ${port} -m conntrack --ctstate NEW -j ACCEPT"
qvm-run -p -u root ${fw} "${exefw}"
exevm="iptables -I INPUT 5 -p tcp --dport ${port} -m conntrack --ctstate NEW -j ACCEPT"
qvm-run -p -u root ${appvm} "${exevm}"
@Joeviocoe
Copy link
Author

Joeviocoe commented Feb 10, 2018

Updated version for Qubes 4.0 (RC4 tested)
Usage: qvm-portfwd <vm> <port> <proto> | <vm> clear all
Example: qvm-portfwd webserv 8888 tcp

Command line specify the "VM, Port and Protocol"... or just "VM clear all" to undo previous.
Script will recursively configure iptables/nft for all proxyVMs in use.
Now uses comments on iptables to remove previous entries (no duplicates)

Works with Fedora 25/26 which uses nft rules along with iptables
Works with Debian 8/9 too

@jpouellet
Copy link

[[ ... =~ .. ]] is a bashism, but you're using /bin/sh (which is not guaranteed to be bash)

Also, for safety and portability I'd suggest:

  • [ X"$foo" = Xbar ] or [ bar = "$foo" ] instead of [[ $foo = bar ]]
  • [ ... -a ... ] / [ ... -o ... ] instead of [[ ... && ... ]] / [[ ... || ...]].

Otherwise nice, and your script is probably better than mine. 🍻

@jpouellet
Copy link

jpouellet commented Jun 25, 2018

Also, I don't like how you're reaching into a VM to grab nft_handle, processing the (untrusted!) result in dom0, and then using the result to decide whether to issue another command. A safer way would be to issue only one command which does the checking and conditional command entirely on the VM, discarding any output back to dom0. Might be over-paranoid, but then again, we had shellshock.

... | grep -qx '[0-9]+' && ( ... ) in the command passed to the VM should do it and remove the bashism at the same time.

@AlphaMufasaOmega
Copy link

AlphaMufasaOmega commented Sep 12, 2018

how do i use/install this on Qubes 4.0 I need to port forward correctly on Qubes 4.0 and and also I have a router so kinda confusing... any help is appreciated! thanks

@w1k1n9cc
Copy link

Simpy put it in ~/bin in dom0 or any other directory in your PATH and use it. Here is an example how I use it for samba:

#!/bin/sh

# Configure ports for samba server
qvm-portfwd server 445 tcp
qvm-portfwd server 445 udp
qvm-portfwd server 139 tcp
qvm-portfwd server 138 udp
qvm-portfwd server 137 udp

# and make conncections between VMS
qvm-portfwd server 445 tcp work
qvm-portfwd server 445 udp work
qvm-portfwd server 139 tcp work
qvm-portfwd server 138 udp work
qvm-portfwd server 137 udp work

I hope that I didn't make any changes. But I don't think so.

@AlphaMufasaOmega
Copy link

AlphaMufasaOmega commented Sep 17, 2018

this sounds really stupid but what is the exact command to do that?

`
qvm-portfwd PTFAssaultMachine 443 tcp

isn't working lol i can get the file into dom0 but it wont recognize the command

for the command

 sudo nano /rw/config/rc.local

#!/bin/sh


####################
# My service routing

# Create a new firewall natting chain for my service
if iptables -t nat -N MY-HTTPS; then

# Add a natting rule if it did not exit (to avoid cluter if script executed multiple times)
  iptables -t nat -A MY-HTTPS -j DNAT --to-destination 10.137.1.x

fi


# If no prerouting rule exist for my service
if ! iptables -t nat -n -L PREROUTING | grep --quiet MY-HTTPS; then

# add a natting rule for the traffic (same reason)
  iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -d 192.168.0.x -j MY-HTTPS
fi


######################
# My service filtering

# Create a new firewall filtering chain for my service
if iptables -N MY-HTTPS; then

# Add a filtering rule if it did not exit (to avoid cluter if script executed multiple times)
  iptables -A MY-HTTPS -s 192.168.x.0/24 -j ACCEPT

fi

# If no forward rule exist for my service
if ! iptables -n -L FORWARD | grep --quiet MY-HTTPS; then

# add a forward rule for the traffic (same reason)
  iptables -I FORWARD 2 -d 10.137.1.x -p tcp --dport 443 -m conntrack --ctstate NEW -j MY-HTTPS

fi

    Note: Again in R4 the following needs to be added:

#############
# In Qubes R4

# If not already present
if nft -nn list table ip qubes-firewall | grep "tcp dport 443 ct state new"; then

# Add a filtering rule
  nft add rule ip qubes-firewall forward meta iifname eth0 ip daddr 10.137.0.x tcp dport 443 ct state new counter accept

fi

Finally make this file executable, so it runs at each boot

sudo chmod +x /rw/config/rc.local 

what is MY-HTTPS referring to? it is confusing me lol its on

https://www.qubes-os.org/doc/firewall/#port-forwarding-to-a-qube-from-the-outside-world

also what does this mean for me(at the bottom of the same page mentioned):

Where to put firewall rules (R4.0)

Implicit in the above example scripts, but worth calling attention to: for all qubes except AppVMs supplying networking, iptables commands should be added to the /rw/config/rc.local script. For AppVMs supplying networking (sys-firewall inclusive), iptables commands should be added to /rw/config/qubes-firewall-user-script.

if i have a basic configuration with app machines : firewall sys-net and PTFAssaultMachine with all three being App machines, also i have a WiFi router and I am wondering if that matters

@npodonnell
Copy link

This is awesome! - worked like a charm.

Thanks

@thavlik
Copy link

thavlik commented Jun 5, 2019

This works well for me. As the instructions said, put it in dom0's ~/bin directory. I used the following instructions:
https://www.qubes-os.org/doc/copy-from-dom0/

From my debian-9 vm, it was:

qvm-run --pass-io debian-9 'cat /home/user/Downloads/qvm-portfwd' > ~/bin/qvm-portfwd
chmod +x ~/bin/qvm-portfwd

Good luck to all others.

@Joeviocoe
Copy link
Author

[[ ... =~ .. ]] is a bashism, but you're using /bin/sh (which is not guaranteed to be bash)

Also, for safety and portability I'd suggest:

* `[ X"$foo" = Xbar ]` or `[ bar = "$foo" ]` instead of `[[ $foo = bar ]]`

* `[ ... -a ... ]` / `[ ... -o ... ]` instead of `[[ ... && ... ]]` / `[[ ... || ...]]`.

Otherwise nice, and your script is probably better than mine. beers
Also, I don't like how you're reaching into a VM to grab nft_handle, processing the (untrusted!) result in dom0....

Thanks. I haven't had time to implement these changes but they are good changes to make.

Honestly, I use a new script that is more in line with Qubism (not Picasso). Everything I need for port fowarding is TCP based... so this script is much safer and uses socat over Qubes own RPC. It connects the net-vm directly to the app-vm without the need for either NFT or IPtables on a proxy-vm/firewall.

It requires some 'install' commands outside/prior to the script... but that could be scripted as well.
https://gist.github.com/Joeviocoe/90ec9fd9a0769b4671a8ae9c87584187

@100111001
Copy link

Dear @Joeviocoe are the changes applied persistent upon next reboot or even beyond that?

@schichtnudelauflauf
Copy link

Why this double fw thing tho?
nf and ip tables

@fepitre
Copy link

fepitre commented Dec 22, 2019

In case someone wants to test, I improved a little bit the current version (https://gist.github.com/fepitre/941d7161ae1150d90e15f778027e3248), notably by adding option for persistence. I'll do some review again (and from others I hope) and we will probably refactor it a little bit again for putting it in @QubesOS-contrib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment