Skip to content

Commit e9c345c

Browse files
committed
feat: create rich rule for NAT port forwarding
Introduce helper to generate IPv4 rich rules mapping SIP ports 5060/5061 to alternate targets when proxy is behind NAT. Ensure previous rules are removed before applying updates, preventing stale firewall entries. Also store multiple local networks in environment, improving flexibility for multi-subnet deployments.
1 parent b4b659c commit e9c345c

File tree

1 file changed

+58
-10
lines changed

1 file changed

+58
-10
lines changed

imageroot/actions/configure-module/20configure

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,84 @@ data = json.load(sys.stdin)
1515

1616
local_networks = set()
1717

18+
# Function to create rich rules for port forwarding
19+
def create_port_forward_rules(local_networks_list, private_ip):
20+
"""Create rich rules for each local network"""
21+
rules = []
22+
for network in local_networks_list:
23+
if network: # Skip empty networks
24+
# Port forward 5060 UDP to 6060
25+
rules.append(f'rule family=ipv4 source address={network} forward-port port=5060 protocol=udp to-port=6060 to-addr={private_ip}')
26+
# Port forward 5060 TCP to 6060
27+
rules.append(f'rule family=ipv4 source address={network} forward-port port=5060 protocol=tcp to-port=6060 to-addr={private_ip}')
28+
# Port forward 5061 TCP to 6061
29+
rules.append(f'rule family=ipv4 source address={network} forward-port port=5061 protocol=tcp to-port=6061 to-addr={private_ip}')
30+
return rules
31+
1832
if "addresses" in data:
1933

2034
address = data["addresses"]
2135

2236
# Set public and private IP
2337
if "public_address" not in address:
2438
# if there's no public address, the proxy is not behind NAT
39+
40+
# Clean up any existing port forwarding rich rules based on previous configuration
41+
prev_localnetworks = agent.get_env("LOCALNETWORKS")
42+
prev_private_ip = agent.get_env("PRIVATE_IP")
43+
if prev_localnetworks and prev_private_ip:
44+
prev_networks = [n for n in prev_localnetworks.split(",") if n]
45+
previous_rules = create_port_forward_rules(prev_networks, prev_private_ip)
46+
if previous_rules:
47+
result = agent.remove_rich_rules(previous_rules)
48+
if not result:
49+
print("Warning: Failed to remove some rich rules", file=sys.stderr)
50+
2551
agent.set_env("PUBLIC_IP", address["address"])
2652
agent.set_env("PRIVATE_IP", "")
2753
agent.set_env("BEHIND_NAT", "false")
2854
agent.unset_env("LOCALNETWORKS")
2955
else:
30-
# if there's a public address, the proxy is behind NAT
56+
# If there's a public address, the proxy is behind NAT
57+
58+
# Get local network from routing table (excluding default route)
59+
detected_network = os.popen("ip route | grep -v default | grep 'src " + address["address"] + "' | awk '{print $1}'").read().strip()
60+
if detected_network:
61+
local_networks.add(detected_network)
62+
63+
# Check if local_networks field is present in data
64+
if "local_networks" in data and data["local_networks"]:
65+
# Add extra local networks
66+
local_networks.update(set(data["local_networks"]))
67+
68+
# Remove existing port forwarding rules based on previous configuration before adding new ones
69+
prev_localnetworks = agent.get_env("LOCALNETWORKS")
70+
prev_private_ip = agent.get_env("PRIVATE_IP")
71+
if prev_localnetworks and prev_private_ip:
72+
prev_networks = [n for n in prev_localnetworks.split(",") if n]
73+
previous_rules = create_port_forward_rules(prev_networks, prev_private_ip)
74+
if previous_rules:
75+
agent.remove_rich_rules(previous_rules)
76+
3177
agent.set_env("PUBLIC_IP", address["public_address"])
3278
agent.set_env("PRIVATE_IP", address["address"])
3379
agent.set_env("BEHIND_NAT", "true")
3480

35-
# Get local network from routing table (excluding default route)
36-
local_networks.add(os.popen("ip route | grep -v default | grep 'src " + address["address"] + "' | awk '{print $1}'").read().strip())
37-
agent.set_env("LOCALNETWORKS", list(local_networks)[0])
81+
# Store local networks
82+
if local_networks:
83+
agent.set_env("LOCALNETWORKS", ",".join(local_networks))
84+
85+
# Create and apply new port forwarding rules for each local network
86+
if local_networks:
87+
new_rules = create_port_forward_rules(list(local_networks), address["address"])
88+
if new_rules:
89+
result = agent.add_rich_rules(new_rules)
90+
if not result:
91+
print("Warning: Failed to add some rich rules", file=sys.stderr)
3892

3993
agent.set_env("DEFAULT_CONTACT", address["address"] + ":5060" if "public_address" not in address else address["public_address"] + ":5060")
4094

4195
if "service_net" in data:
4296
service = data["service_net"]
4397
agent.set_env("SERVICE_IP", service["address"])
4498
agent.set_env("SERVICE_NET", service["netmask"])
45-
46-
#check if local_networks is not empty and local_networks filed is present in data
47-
if local_networks and "local_networks" in data:
48-
# Add extra local networks
49-
local_networks.update(set(data["local_networks"]))
50-
agent.set_env("LOCALNETWORKS", ",".join(local_networks))

0 commit comments

Comments
 (0)