Skip to content

Instantly share code, notes, and snippets.

@vdbsh
Last active August 21, 2023 15:36
Show Gist options
  • Save vdbsh/cc129c90e978a1ddb222446f68e67080 to your computer and use it in GitHub Desktop.
Save vdbsh/cc129c90e978a1ddb222446f68e67080 to your computer and use it in GitHub Desktop.
Maps network ports thru NAT-PMP and refreshes that mapping automatically
#!/usr/bin/env bash
# natpmprfr.sh: Maps network ports thru NAT-PMP and refreshes that mapping automatically
# (https://en.wikipedia.org/wiki/NAT_Port_Mapping_Protocol)
#
# Useful for applications with poor or without NAT-PMP implementation
# (http://miniupnp.free.fr/libnatpmp.html)
#
# Script can set UFW rules according to mapped/unmapped local ports
# (https://help.ubuntu.com/community/UFW)
#
# Requirements: sudo, natpmpc, ufw (optional)
# Tested on Ubuntu 22.04 LTS
gateway="192.168.1.1" # mat-pmp gateway
private_port="0" # set 0 to obtain from natpmpc
protocols="tcp" # "tcp" "udp" "tcp udp"
refresh_timeout="40" # seconds
port_file="/tmp/nat-pmp_local_port.txt" # leave "" to disable
set_ufw_rules=true # requires root permissions
map_port() {
if [[ "$protocols" == *"tcp"* ]]; then
natpmc_out=$(sudo -u nobody natpmpc -g "$gateway" -a 0 "$local_port" tcp 60)
local_port=$(echo "$natpmc_out" | grep -Po 'local\sport\s\K\d{0,65535}')
public_port=$(echo "$natpmc_out" | grep -Po 'public\sport\s\K\d{0,65535}')
echo "πŸ’» Local TCP port: $local_port" >/dev/tty
echo "🌐 Public TCP port: $public_port" >/dev/tty
fi
if [[ "$protocols" == *"udp"* ]]; then
natpmc_out=$(sudo -u nobody natpmpc -g "$gateway" -a 0 "$local_port" udp 60)
local_port=$(echo "$natpmc_out" | grep -Po 'local\sport\s\K\d{0,65535}')
public_port=$(echo "$natpmc_out" | grep -Po 'public\sport\s\K\d{0,65535}')
echo "πŸ’» Local UDP port: $local_port" >/dev/tty
echo "🌐 Public UDP port: $public_port" >/dev/tty
fi
if [ -n "$local_port" ]; then
echo "$local_port"
fi
}
ufw_open_port() {
if [ "$set_ufw_rules" = true ]; then
echo ""
echo "🧱 UFW says:"
if [ "$local_port" = "0" ]; then
ufw allow "$1"
else
ufw allow "$local_port"
fi
fi
}
ufw_close_port() {
if [ "$set_ufw_rules" = true ]; then
echo ""
echo "🧱 UFW says:"
if [ "$local_port" = "0" ]; then
ufw delete allow "$1"
else
ufw delete allow "$local_port"
fi
fi
}
write_port_to_file() {
if [ -n "$port_file" ]; then
echo "$1" | sudo -u nobody tee "$port_file" 1>/dev/null
fi
}
unmap_ports() {
echo ""
echo "🌊 Unmapping port(s)..."
if [ -n "$cached_local_port" ]; then
if [[ "$protocols" == *"tcp"* ]]; then
sudo -u nobody natpmpc -g "$gateway" -a "$cached_local_port" "$local_port" tcp 0 1>/dev/null
fi
if [[ "$protocols" == *"udp"* ]]; then
sudo -u nobody natpmpc -g "$gateway" -a "$cached_local_port" "$local_port" udp 0 1>/dev/null
fi
ufw_close_port "$cached_local_port"
fi
}
terminate() {
unmap_ports
rm -f "$port_file"
exit
}
if [ "$set_ufw_rules" = true ]; then
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
fi
trap terminate SIGINT SIGTERM SIGQUIT SIGABRT
echo "🌎 Getting info..."
if sudo -u nobody natpmpc -g "$gateway"; then
while true; do
echo ""
echo "πŸ”Œ Mapping ${protocols^^} port(s)..."
local_port=$(map_port)
if [ -n "$local_port" ]; then
ufw_open_port "$local_port"
write_port_to_file "$local_port"
cached_local_port="$local_port"
else
echo ""
echo "πŸ’’ Something went wrong..."
if [ -n "$cached_local_port" ]; then
unmap_ports
cached_local_port=""
rm -f "$port_file"
fi
fi
echo ""
echo "πŸ”„ Refreshing ($(date))..."
sleep "$refresh_timeout"
done
else
exit
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment