Utils for port forwarding using iptables on a single NIC Proxmox VE machine. Suppose your intranet subnet is 192.168.0.0/24, the public IP is 1.2.3.4 & the NIC is vmbr0.
#!/usr/bin/env python3 | |
import argparse | |
import ipaddress | |
import os | |
INTERNAL_SUBNET = "192.168.0.0/24" | |
INTERNET_ADDRESS = "1.2.3.4" | |
INTERFACE = "vmbr0" | |
def get_args(): | |
parser = argparse.ArgumentParser(description="Add a port forwarding rule.") | |
parser.add_argument("--port", type=int, metavar="{1...65535}", help="Host port where traffic comes from.", | |
required=True) | |
parser.add_argument("--protocol", type=str, help="Port protocol to use.", choices=("tcp", "udp", "all"), | |
default="tcp") | |
parser.add_argument("internal_address", type=str, help="Internal address to be forwarded to.") | |
args = parser.parse_args() | |
listen_port = args.port | |
if not 0 < listen_port < 65536: | |
parser.error("invalid host port") | |
protocols = (args.protocol,) if args.protocol != "all" else ("tcp", "udp") | |
internal_address = args.internal_address | |
ip, separator, port = internal_address.rpartition(":") | |
try: | |
assert separator | |
assert ipaddress.ip_address(ip) in ipaddress.ip_network(INTERNAL_SUBNET) | |
port = int(port) | |
assert 0 < port < 65536 | |
except Exception as _: | |
parser.error("invalid internal address") | |
return listen_port, ip, port, protocols | |
def main(): | |
listen_port, internal_ip, internal_port, protocols = get_args() | |
print("executing iptables commands...") | |
for protocol in protocols: | |
commands = ( | |
f"iptables -t nat -A PREROUTING -d {INTERNET_ADDRESS}/32 -i {INTERFACE} -p {protocol} " | |
f"--dport {listen_port} -j DNAT --to-destination {internal_ip}:{internal_port}", | |
f"iptables -A FORWARD -d {internal_ip}/32 -p {protocol} --dport {internal_port} " | |
f"-m state --state NEW,ESTABLISHED,RELATED -j ACCEPT", | |
) | |
for c in commands: | |
print(c) | |
os.system(c) | |
if __name__ == "__main__": | |
main() |
#!/usr/bin/env python3 | |
import argparse | |
import ipaddress | |
import os | |
INTERNAL_SUBNET = "192.168.0.0/24" | |
INTERNET_ADDRESS = "1.2.3.4" | |
INTERFACE = "vmbr0" | |
def get_args(): | |
parser = argparse.ArgumentParser(description="Delete a port forwarding rule.") | |
parser.add_argument("--port", type=int, metavar="{1...65535}", help="Host port where traffic comes from.", | |
required=True) | |
parser.add_argument("--protocol", type=str, help="Port protocol to use.", choices=("tcp", "udp", "all"), | |
default="tcp") | |
parser.add_argument("internal_address", type=str, help="Internal address to be forwarded to.") | |
args = parser.parse_args() | |
listen_port = args.port | |
if not 0 < listen_port < 65536: | |
parser.error("invalid host port") | |
protocols = (args.protocol,) if args.protocol != "all" else ("tcp", "udp") | |
internal_address = args.internal_address | |
ip, separator, port = internal_address.rpartition(":") | |
try: | |
assert separator | |
assert ipaddress.ip_address(ip) in ipaddress.ip_network(INTERNAL_SUBNET) | |
port = int(port) | |
assert 0 < port < 65536 | |
except Exception as _: | |
parser.error("invalid internal address") | |
return listen_port, ip, port, protocols | |
def main(): | |
listen_port, internal_ip, internal_port, protocols = get_args() | |
print("executing iptables commands...") | |
for protocol in protocols: | |
commands = ( | |
f"iptables -t nat -D PREROUTING -d {INTERNET_ADDRESS}/32 -i {INTERFACE} -p {protocol} " | |
f"--dport {listen_port} -j DNAT --to-destination {internal_ip}:{internal_port}", | |
f"iptables -D FORWARD -d {internal_ip}/32 -p {protocol} --dport {internal_port} " | |
f"-m state --state NEW,ESTABLISHED,RELATED -j ACCEPT", | |
) | |
for c in commands: | |
print(c) | |
os.system(c) | |
if __name__ == "__main__": | |
main() |
#!/bin/sh | |
echo "reloading IPv4 rules from iptables-persistent..." | |
iptables --flush | |
iptables --table nat --flush | |
iptables --delete-chain | |
iptables --table nat --delete-chain | |
iptables -F | |
iptables -X | |
iptables-restore < /etc/iptables/rules.v4 |
# Initial iptables config for NAT. | |
*nat | |
:PREROUTING ACCEPT [0:0] | |
:INPUT ACCEPT [0:0] | |
:OUTPUT ACCEPT [0:0] | |
:POSTROUTING ACCEPT [0:0] | |
-A POSTROUTING -s 192.168.0.0/24 -o vmbr0 -j SNAT --to-source 1.2.3.4 | |
COMMIT | |
*raw | |
:PREROUTING ACCEPT [0:0] | |
:OUTPUT ACCEPT [0:0] | |
COMMIT | |
*filter | |
:INPUT ACCEPT [0:0] | |
:FORWARD ACCEPT [0:0] | |
:OUTPUT ACCEPT [0:0] | |
-A FORWARD -s 192.168.0.0/24 -i vmbr0 -o vmbr0 -j ACCEPT | |
-A FORWARD -i vmbr0 -o vmbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT | |
COMMIT |
#!/bin/sh | |
echo "saving IPv4 rules for iptables-persistent..." | |
iptables-save > /etc/iptables/rules.v4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment