Create a gist now

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

This comment has been minimized.

Show comment
Hide comment
@Joeviocoe

Joeviocoe 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

Owner

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

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet Jun 25, 2018

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

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

This comment has been minimized.

Show comment
Hide comment
@jpouellet

jpouellet 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.

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.

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