Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Qubes-os port forwarding to allow external connections
#!/bin/sh
# Inspired by https://gist.github.com/daktak/f887352d564b54f9e529404cc0eb60d5
# Inspired by https://gist.github.com/jpouellet/d8cd0eb8589a5b9bf0c53a28fc530369
ip() { qvm-prefs -g -- "$1" ip; }
netvm() { qvm-prefs -g -- "$1" netvm; }
forward() {
local from_domain=$1
local to_domain=$2
local port=$3
local type=$4
local from_ip=$(ip "$from_domain")
local to_ip=$(ip "$to_domain")
local iface=$(qvm-run -p -u root "$from_domain" "ifconfig \
| grep cast -B 1 --no-group-separator | grep -vE '^(vif|lo)' | grep -oE '^[^: ]+' | head -1")
local from_ip=$(qvm-run -p -u root "$from_domain" "hostname -I | cut -d ' ' -f 1")
if [ X"$from_ip" = XNone ] ; then local from_ip= ; fi
if [[ $3 = "clear" && $4 = "all" ]]
then
echo "$from_domain: Clearing Port Forwarding from $1 iptables" >&2
qvm-run -p -u root "$from_domain" "iptables-save | grep -v 'PortFwd $1' | iptables-restore"
local nft_cmd="nft list table ip qubes-firewall -a | tr -d '\"' | grep 'iifname $iface accept # handle' | awk '{print \$NF}'"
local nft_handle=$(qvm-run -p -u root "$from_domain" "$nft_cmd")
if [[ $nft_handle =~ ^[0-9]+$ ]] ; then qvm-run -p -u root "$from_domain" "nft delete rule ip qubes-firewall forward handle $nft_handle" ; fi
else
echo "$from_domain: Forwarding on $iface port $port to $to_domain
($from_ip -> $to_ip)" >&2
qvm-run -p -u root "$from_domain" "iptables-save | grep -v 'PortFwd $1>$2:$4$3' | iptables-restore"
qvm-run -p -u root "$from_domain" "iptables -t nat -A PREROUTING -i $iface -p $type ${from_ip:+-d} $from_ip --dport $port -j DNAT --to-destination $to_ip \
-m comment --comment 'PortFwd $1>$2:$4$3'"
qvm-run -p -u root "$from_domain" "iptables -I FORWARD 2 -i $iface -p $type ${to_ip:+-d} $to_ip --dport $port -m conntrack --ctstate NEW -j ACCEPT \
-m comment --comment 'PortFwd $1>$2:$4$3'"
qvm-run -p -u root "$from_domain" "nft add rule ip qubes-firewall forward meta iifname $iface accept"
fi
}
input() {
local domain=$1
local port=$2
local type=$3
if [[ $2 = "clear" && $3 = "all" ]]
then
echo "$domain: Clearing Port Forwarding from $1 iptables" >&2
qvm-run -p -u root "$domain" "iptables-save | grep -v 'PortFwd $1' | iptables-restore"
else
echo "$domain: Allowing input to port $port" >&2
qvm-run -p -u root "$domain" "iptables-save | grep -v 'PortFwd $1:$3$2' | iptables-restore"
qvm-run -p -u root "$domain" "iptables -I INPUT 5 -p $type --dport $port -m conntrack --ctstate NEW -j ACCEPT \
-m comment --comment 'PortFwd $1:$3$2'"
fi
}
recurse_netvms() {
local this_dom=$1
local port=$2
local type=$3
local outer_dom=$(netvm "$this_dom")
if [[ -n "$outer_dom" && "$outer_dom" != "None" ]]; then
forward "$outer_dom" "$this_dom" "$port" "$type"
recurse_netvms "$outer_dom" "$port" "$type"
fi
}
usage() {
echo "Usage: ${0##*/} <vm> <port> <proto> | <vm> clear all" >&2
exit 1
}
[ $# -eq 3 ] || usage
input "$1" "$2" "$3"
recurse_netvms "$1" "$2" "$3"
@Joeviocoe
Copy link
Author

Joeviocoe commented Jun 6, 2019

[[ ... =~ .. ]] 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

100111001 commented Oct 4, 2019

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

@AngryLasagna
Copy link

AngryLasagna commented Nov 24, 2019

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