GL-BE9300: Port forwarding broken after upgrading to 4.9.0 (port_forward kernel module fails)

Model: GL-BE9300 (Flint 3) Firmware: 4.8.4 → 4.9.0

Issue: After upgrading from 4.8.4 to 4.9.0, port forwarding stopped working completely. The web UI shows the rules correctly, but they are not applied.

Root cause identified via CLI:

In 4.8.4, port forwarding rules are correctly generated in nftables:

chain dstnat_wgclient1 {
    meta nfproto ipv4 tcp dport 443 dnat ip to 192.168.60.201:443
    meta nfproto ipv4 tcp dport 12222 dnat ip to 192.168.60.201:12222
    ...
}

In 4.9.0, a new kernel module port_forward is used instead, but it fails:

# cat /proc/port_forward
cat: read error: I/O error

# /usr/bin/port_forward.lua
(no output, no error, but rules not applied)

The dstnat_wgclient1 chain no longer exists in 4.9.0, and the kernel module cannot write rules to /proc/port_forward.

Workaround: Downgraded back to 4.8.4, which works correctly.

Request: Please fix the port_forward kernel module in 4.9.0, or provide a way to fall back to the nftables-based implementation.

I've been on 4.9.0 for a while. Port forwarding is working fine on my Flint 3 (using the GUI).

Did you keep your old settings during the update? That didn't go well for me. I had to do a clean install which fixed my issues.

Yes, I kept the old settings during the update.

However, I noticed an interesting behavior: port forwarding worked from my VPS (which connects via WireGuard as a peer on the same tunnel), but not from an external PC connecting through the VPS via DNAT.

After investigation via CLI, I found that in 4.8.4, conntrack entries for DNAT'd connections have mark=0x1000, which correctly routes the return packets back through the wgclient1 interface. In 4.9.0, the mark was 0, causing return packets to go out through the WAN interface instead, breaking the connection for external clients.

This suggests the issue is specifically with the port_forward kernel module failing to set the correct conntrack mark, rather than the DNAT rule itself.

Additional issue: When downgrading from 4.9.0 back to 4.8.4 with "Keep settings" option, port forwarding rules were completely lost. Other settings were preserved correctly.

This is likely because 4.9.0 moved port forwarding configuration from /etc/config/firewall (redirect entries) to /etc/config/port_forward, which 4.8.4 does not recognize.

1 Like

ah this would explain why I was not seeing the GL-iNet portforwards re-appear in the new firmware in the gl ui, I thought it was following a GL_ prefix in luci but it seems it moved to a whole different config!

P.s I was cherry picking pieces of the backup config instead of using the full backup.

Hi

We tested locally using BE9300 v4.9.0 Release 5, and forwarding from the WireGuard client to LAN devices appears to be working correctly.

Configuration:

Packet capture:

As others have suggested, this may be related to preserving the configuration during the firmware upgrade.

If you recreate the relevant port forwarding rules, do they work correctly afterward?

Same problem. Port forward stopped to work after upgrading to 4.9.0, keeping settings

Deleted rules and created again, still no go.

In LuCI firewall peort forward setting, there is no entry at all.

Creating port forward entry in LuCI worked.

So the problem is with GL Inet web GUI

1 Like

Hi

We have performed several additional local tests on this issue, including upgrading from v4.8.4 to v4.9.0 while preserving the configuration. However, we still have not been able to reproduce the problem.

Could you please help provide the following information:

  1. Run the following commands to check whether the port forwarding configuration has been migrated correctly and loaded into the kernel module:

    uci show port_forward
    cat /proc/port_forward_rules
    
  2. If the output of cat /proc/port_forward_rules does not match the output of uci show port_forward, and if possible, could you please follow the guide and share your device with us via GoodCloud so we can check it remotely?

    Technical Support via GoodCloud - GL.iNet Router Docs 4

    Kindly note to send us the MAC address and the router password via private message so we can access it.

Thank you for the follow-up.

I upgraded from v4.8.4 to v4.9.0 with "Keep settings" enabled, as shown in the attached screenshot (dialog.png). The UI is in Japanese, but the "Keep settings" toggle is ON.

Just to clarify: I configured port forwarding using the GL.iNet web GUI (not LuCI). The rules were visible and enabled in the GL web GUI. I also tested deleting and recreating the port forwarding rules via the GL web GUI, as well as rebooting, but the issue persisted.

The output of uci show port_forward and cat /proc/port_forward_rules is attached as output.txt.

I found the root cause by checking conntrack entries. I verified this by running conntrack -L | grep 443 | grep <external-PC-IP> while attempting an HTTPS connection from the external PC. The key difference between v4.8.4 and v4.9.0 is the conntrack mark value:

  • v4.8.4: mark=0x1000 (4096) → matches ip rule fwmark 0x1000/0xf000 → return packets correctly routed via wgclient1

  • v4.9.0: mark=0x10000 (65536) → does NOT match ip rule fwmark 0x1000/0xf000 → return packets go out via WAN instead of wgclient1, breaking the connection

Note that my setup involves an external PC connecting through a VPS via DNAT, then through WireGuard (wgclient1) to the LAN. Port forwarding works correctly when connecting directly from the VPS (10.0.0.254), but fails for external clients whose traffic is DNAT'd through the VPS. This may be specific to WireGuard client setups where correct conntrack marking is required for proper return routing.

I would prefer not to share device credentials or grant remote access via GoodCloud due to security concerns. However, I am happy to provide additional CLI output if needed. We can proceed step by step.

output.txt (6.1 KB)

Here is my network topology for reference:

[External PC] xx.xx.xx.xx
  |
  | (WAN)
  |
[VPS] yy.yy.yy.yy (Global IP) / 10.0.0.254 (WireGuard IP)
  | iptables DNAT: yy.yy.yy.yy -> 10.0.0.2
  |
  | (WireGuard tunnel)
  |
[GL-BE9300] 10.0.0.2 (WireGuard IP) / 192.168.60.254 (LAN IP)
  | Port Forwarding: 10.0.0.2 -> 192.168.60.201
  |
  | (LAN)
  |
[Server] 192.168.60.201

This specific topology may be required to reproduce the issue. The problem only manifests when an external PC accesses the server via DNAT on the VPS, through a WireGuard tunnel to the GL-BE9300, and then via port forwarding to the LAN server. Connecting directly from the VPS (10.0.0.254) works correctly, as the return packets naturally go back through the WireGuard tunnel without requiring the correct fwmark.

With this setup, port forwarding works correctly when connecting directly from the VPS (10.0.0.254), but fails for the external PC (xx.xx.xx.xx) whose traffic is DNAT'd through the VPS. This is because the return packets need to be routed back via wgclient1, which requires the correct fwmark to be set.

I also analyzed how the conntrack mark is used in the routing process.

In v4.8.4, the following nftables rules exist to synchronize the conntrack mark (ctmark) with the packet mark (fwmark):

iifname "wgclient1" ... ct state new ct mark set ct mark & 0xffff1fff | 0x00001000  (wgclient1_in_new_connmark)
ct mark & 0x0000f000 != 0x00000000 jump mark_ct_to_meta
ct mark & 0x0000f000 == 0x00001000 meta mark set meta mark & 0xffff1fff | 0x00001000  (wgclient1_mark_ct_to_meta)

This means:

  1. New connections from wgclient1 are assigned ctmark 0x1000

  2. The mark_ct_to_meta chain propagates ctmark to fwmark

  3. The ip rule fwmark 0x1000/0xf000 matches, and return packets are correctly routed via wgclient1

In v4.9.0, the conntrack mark observed was 0x10000 instead of 0x1000. Since the ip rule still uses fwmark 0x1000/0xf000, the mask 0xf000 applied to 0x10000 results in 0x0000, which does not match. Therefore, return packets are not routed via wgclient1 and go out via WAN instead, making the service unreachable from the external PC.

The issue appears to be that the port_forward kernel module in v4.9.0 is setting the conntrack mark to 0x10000 instead of 0x1000, breaking the routing for WireGuard client setups.