Off the top of my head, this might work. At least, I think the concept is sound, even if I haven't tested the execution...
Keep a persistent record of the gateway IP address each time (e.g. in a text file on persistent storage)
Next time the router reboots, calculate the new gateway IP address
Then retrieve the old gateway IP address from wherever you stored it
Edit /etc/config/firewall and replace the old gateway IP address with the new gateway IP address (the rest of the rule doesn't need to change, only the destination IP address) - sed is good for replacing text automatically.
Then restart the firewall service
To get the above to work, you'll need to learn a bit of shell scripting and the use of variables.
config redirect
option name 'droid'
option family 'ipv4'
option target 'DNAT'
option src 'lan'
option src_dport '32398-32400'
option dest 'wan'
option dest_ip '192.168.192.168'
option dest_port '32398-32400'
/etc/config/firewallafter a change:
config redirect
option name 'droid'
option family 'ipv4'
option target 'DNAT'
option src 'lan'
option src_dport '32398-32400'
option dest 'wan'
option dest_ip '192.168.7.1'
option dest_port '32398-32400'
/etc/scripts/old_gateway.txtbefore any change:
192.168.192.168
/etc/scripts/old_gateway.txtafter a change:
192.168.7.1
/etc/rc.local:
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
# Pause to allow network to come up, or else gateway calculation might fail
sleep 10
# Retrieve previous upstream gateway address
OLD_GATEWAY=`cat /etc/scripts/old_gateway.txt`
# Obtain current upstream gateway address
NEW_GATEWAY=`route | awk '/default/ {print $2;}'`
# Replace gateway address in firewall rule(s)
sed -i s/$OLD_GATEWAY/$NEW_GATEWAY/g /etc/config/firewall
# Store new gateway address as "old" address for next reboot
echo $NEW_GATEWAY>/etc/scripts/old_gateway.txt
# Restart the firewall
/etc/init.d/firewall restart
exit 0
Something along those lines, yes. I just posted something which I whipped up on my system and seems to work.
Be aware, there is no error checking or other safety nets beyond a 10-second delay to allow the WAN interface to come up and obtain a route. It's very crude, and not resilient at all.
Another option to consider is to use /etc/udhcpc.user or /etc/udhcpc.user.d/ which would be invoked on a WAN DHCP event and use the $router environment variable provided by udhcpc to update the firewall rule.
Edit: added a check in case the IP hasn’t changed. This also assumes the redirect to be changed is the last one in the ruleset [-1]. If not, adjust accordingly.
Heads up: bare route gives me a symbolic name for $2, so I added the "numeric" option, route -n to force the IP address... (I suspect it depends on whether your ISP has DNS for their endpoint routers.)
Interesting. Thanks for the warning. I may need to revisit the behaviour of the route command, as well as my understanding of awk's behaviour.
I settled on that approach because I wanted something unique and the word "default" was unique. Parsing the second entry in the awk array was then easy to accomplish. When I originally tried using route -n, awk ended up returning more than one result.
I'll go back to the drawing board and see if I can come up with something a bit more robust. Thanks again.
Oh, I didn't even notice that it did the default -> 0.0.0.0 thing. I've always used something like below (probably just because I forgot about route and ifstatus always seems to be a good grab-bag for this sort of stuff, although those jsonfilter espressions can be pretty tedious).
$ ifstatus wan | jsonfilter -e '@.route[0].nexthop'
EDIT
Just playing around, this might be more robust ... doing a search through all the routes for the default.
$ ifstatus wan | jsonfilter -e '@.route[@.target="0.0.0.0"].nexthop'
61.3.190.1