I have had for sometime a script on my Linux devices and on my mother's Windows PC at her place a script that will open specific ports, namely for ssh and a vpn on the firewalls for specific address. Essentially the functionality is every 10 minutes or so it looks up a couple of dynamic dns address and opens a port on the fire wall for those devices or if the port is already open updates the address if it varies from that already there. If I am out and about or my ISP updates then I need only wait a max of 10 minutes or so and I can access again.
I've just swapped my ISP router out for a Pi4B with an OpenWRT snapshot, everything seems to be working got the DNS hijack to force queries to the PiHole etc. Now what I'd like to do if it is possible is to replicate the scripts that are updating UFW on my Linux devices to the new router in place of the direct port forwards I copied over form the ISP router. However, I am really not sure how to do this.
Is that correct? What would be the syntax to add/modify these from cli/script?
Is anyone is aware of an exiting script to do this or do I need to use the ufw one as a base?
Looks like you are making it more complicated than necessary.
Since you already have a VPN, there's no need to expose other ports.
Just open the VPN port on the WAN and assign the VPN network to your LAN zone.
While I do mostly use it I also run some servers for family too, principally FTP, I'd also like to lock down the VPN just to my devices. I made a bit of a start on the logic, just getting the addresses, wondered about using UCI to modify/delete the rules if addresses have changed.
#!/bin/sh
#set -x
# Some variables
LAPTOP=`dig +short laptop.freeddns.org`
MOBILE=`dig +short mobile.freeddns.org`
MUM=`dig +short mum.freeddns.org`
LISS=`dig +short liss.freeddns.org`
#
# Read saved addresses
laptop=`cat LAPTOP.sav`
mobile=`cat MOBILE.sav`
mum=`cat MUM.sav`
liss=`cat LISS.sav`
# Now do stuff
if [ $LAPTOP = $laptop ]; then echo "Matched"; else echo "Mismatched"; fi
if [ $MOBILE = $mobile ]; then echo "Matched"; else echo "Mismatched"; fi
if [ $MUM = $mum ]; then echo "Matched"; else echo "Mismatched"; fi
if [ $LISS = $liss ]; then echo "Matched"; else echo "Mismatched"; fi
# If mismatch need to deleted old rule, add new one, update saved address otherwise exit.
I assume, that you have the package bind-dig installed and working.
This is an example for the laptop. You'll have to multiply the rules for the other devices.
Create the initial rule(s) in /etc/firewall.user
#Get the laptop public IP address
LAPTOP=$(dig +short laptop.freeddns.org)
#If the IP address cannot be found, use some dummy IP address to create the rule
if [ -z "$LAPTOP" ]; then
LAPTOP="123.123.123.123"
fi
#Save the current laptop IP address
echo "$LAPTOP" > /tmp/LAPTOP.sav
#Create the DNAT rules
iptables -t nat -A prerouting_wan_rule -m comment --comment "LAPTOP-TCP" -m tcp -p tcp -s "$LAPTOP"/32 -m multiport --dports 15251:15255 -j DNAT --to-destination 192.168.70.250:15251-15255
iptables -t nat -A prerouting_wan_rule -m comment --comment "LAPTOP-UDP" -m udp -p udp -s "$LAPTOP"/32 -m multiport --dports 15251:15255 -j DNAT --to-destination 192.168.70.250:15251-15255
Here is an example of the update script:
#!/bin/sh
#Get the laptop real IP address
LAPTOP=$(dig +short laptop.freeddns.org)
#Get the last known laptop IP address
laptop=$(cat /tmp/LAPTOP.sav)
#Update the rules if the laptop has a new ip address
if [ ! -z "$LAPTOP" ] && [ "$laptop" != "$LAPTOP" ]; then
#Get the rule numbers
rntcplaptop=$(iptables -t nat -L --line-numbers | grep LAPTOP-TCP | awk '{ print $1 }')
rnudplaptop=$(iptables -t nat -L --line-numbers | grep LAPTOP-UDP | awk '{ print $1 }')
#Replace the rules
iptables -t nat -R prerouting_wan_rule "$rntcplaptop" -m comment --comment "LAPTOP-TCP" -m tcp -p tcp -s "$LAPTOP"/32 -m multiport --dports 15251:15255 -j DNAT --to-destination 192.168.70.250:15251-15255
iptables -t nat -R prerouting_wan_rule "$rnudplaptop" -m comment --comment "LAPTOP-UDP" -m udp -p udp -s "$LAPTOP"/32 -m multiport --dports 15251:15255 -j DNAT --to-destination 192.168.70.250:15251-15255
#Update the laptop IP address
echo "$LAPTOP" > /tmp/LAPTOP.sav
fi
Create a cron job
*/10 * * * * /root/update.scr 1>/dev/null 2>&1
Check your custom rules, running the following command:
Thanks. That gives me the outline to get a working script. In case it is of use to anyone in the future I put in this one line that verifies the IP address and if not uses the previous saved. It only checks for a valid formatted IPv4.
if [[ $LAPTOP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then echo "Good Address"; else LAPTOP=$laptop; echo "Bad Address, using saved"; fi
The only query I am scratching my head over is the Wireguard VPN, how from iptables restrict the source IP in a similar way. Anyway shall keep reading.