Monday, December 25, 2023

Secure openwrt WOL with no open ports (firewall/nat etc...)

The objective of this article is to achieve WOL in a setup where Internet access is behind a NAT or has a firewall which allows no open connections. We'll also cover the security aspect using purely iptables (instead of openwrt's built in firewall) -- this's particularly important since the openwrt installed on the router is outdated and it's discontinued (so it won't receive any security updates).

To achieve WOL, we'll be using a simple shell script which will periodically download a text file and check it's contents; for a certain value within the text file, it'll trigger a WOL for a certain hardware address. Here is the script -- 

#! /bin/ash
while [[ j != k ]]
do
    if test '<wol string>' = "$(wget -q -O - -U 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Edg/91.0.864.37' --no-check-certificate '<URL of text file>')"
    then
        /usr/bin/etherwake -D -i '<interface>' <hardware address of your system>
        sleep 30
    fi
done

For this you need to install the etherwake package.

<wol string> is the string written in the text file. For this string the WOL signal will be emitted. Therefore to disable WOL, you need to modify the text file to anything else other than this string.

<URL of text file> is a HTTP link. This may point to an s3 object which is a good candidate or any online office document (something hosted by google drive). Regardless, you must be directly able to download a text file using the link using wget.

<interface> is the interface via which your to-be-wol system is accessible.

Make a file /usr/bin/wol.sh, write the script there and -- 

chmod 755 /usr/bin/wol.sh

Add /usr/bin/wol.sh to the local startup script (found in luci in the startup page) as -- 

/usr/bin/wol.sh &

 And you're done!

Now for the firewall part. I've disabled the buitin firewall of openwrt because it was not working as expected -- 

service firewall disable

Reboot router.

Add the firewall rules -- 

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -o <router interface> -p icmp -s <router IP> -d <your system IP>,<default gateway IP>,255.255.255.255,<broadcast IP of your subnet> -j ACCEPT
iptables -A INPUT -i <router interface> -p icmp -s <your system IP>,<default gateway IP> -d <router IP>,255.255.255.255,<broadcast IP of your subnet>  -j ACCEPT
iptables -A INPUT -i <router interface> -p tcp -m conntrack --ctstate NEW,RELATED,ESTABLISHED --dport <ssh port of your router> -s <your system IP> -d <router IP> -j ACCEPT
iptables -A OUTPUT -o <router interface> -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -d <your system IP> -s <router IP> --sport <ssh port of your router> -j ACCEPT
iptables -A OUTPUT -o <router interface> -p udp -m conntrack --ctstate NEW,RELATED,ESTABLISHED --dport 53 -d <DNs server IP> -j ACCEPT
iptables -A INPUT -i <router interface> -p udp -m conntrack --ctstate RELATED,ESTABLISHED --sport 53 -s <DNs server IP> -j ACCEPT
iptables -A OUTPUT -o <router interface> -p udp -m conntrack --ctstate NEW,RELATED,ESTABLISHED --dport 123 -d <NTP server IP> -j ACCEPT
iptables -A INPUT -i <router interface> -p udp -m conntrack --ctstate RELATED,ESTABLISHED --sport 123 -s <NTP server IP> -j ACCEPT
iptables -A OUTPUT -o <router interface> -p tcp -m conntrack --ctstate NEW,RELATED,ESTABLISHED -d <list of public IPs> -s <router IP> -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -i <router interface> -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -m multiport --sports 80,443 -s <list of public IPs> -d <router IP> -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

<your system IP> is the system using which you're accessing the router over SSH.

This system of rules assume you access the luci GUI over ssh tunneling which is recommended.

You need to change your ntp servers to something fixed -- otherwise most NTP server DNS has so many IPs behind it... Good luck finding such a service.

<list of public IPs> is the list of public IPs of the service provider hosting your text file which the WOL script will monitor. Best of luck finding that.

After ensuring you're not cut off ssh access (otherwise reboot and then reattempt to fix the firewall rules) -- 

iptables-save > /etc/custom-iptables

Then add to the local startup stript (via luci GUI) -- 

iptables-restore < /etc/custom-iptables

Test all desired functionality.