# OpenWrt package feed for etherwake-nfqueue ## Wake up computers on netfilter match This repository contains the OpenWrt package feed for [etherwake-nfqueue](https://github.com/mister-benjamin/etherwake-nfqueue), a fork of the **etherwake** Wake-on-LAN client, with support to send magic packets only after a queued packet is received from the Linux *nfnetlink_queue* subsystem. When running **etherwake-nfqueue** on a residential gateway or other type of router, it can wake up hosts on its network based on packet filtering rules. For instance, when your set-top box wants to record a TV programme and tries to access a network share on your NAS, which is in sleep or standby mode, **etherwake-nfqueue** can wake up your NAS. Or when you set up port forwarding to a host on your home network, **etherwake-nfqueue** can wake up your host when you try to access it over the Internet. The documentation below is mostly OpenWrt specific. For more information on etherwake-nfqueue itself and use case examples, please consult its [Readme](https://github.com/mister-benjamin/etherwake-nfqueue/blob/master/README.md). ## Building the package Currently, no pre-built packages are provided. The following assumes that you already have a working OpenWrt build system for your target device. If you haven't, you can follow one of these guides: * If you only want to compile packages, and no firmware image: [Build system – Installation](https://openwrt.org/docs/guide-developer/build-system/install-buildsystem) and [Using the SDK](https://openwrt.org/docs/guide-developer/using_the_sdk) * To quickly build a firmware image off a development snapshot: [Quick Image Building Guide](https://openwrt.org/docs/guide-developer/quickstart-build-images) * Or when you are completely new to using build systems: [Beginners guide to building your own firmware](https://openwrt.org/docs/guide-user/additional-software/beginners-build-guide) ### Dependencies **etherwake-nfqueue** depends on these OpenWrt packages: * libnetfilter-queue * iptables-mod-nfqueue They will be automatically selected and compiled for you. If they are not installed on your target device, *opkg* will try to resolve dependencies with packages in the repositories. ### Adding the package feed First, you need to add the **etherwake-nfqueue** package feed to your build system. In the root directory of your OpenWrt build system, find the file *feeds.conf* (or *feeds.conf.default* if the former shouldn't exist) and add the following line to it: ``` src-git ethernfq https://github.com/mister-benjamin/etherwake-nfqueue-openwrt.git ``` Then update and install the package feed: ``` user@host:~/openwrt$ scripts/feeds update ethernfq user@host:~/openwrt$ scripts/feeds install -a -p ethernfq ``` After that, enter OpenWrt's configuration menu ``` user@host:~/openwrt$ make menuconfig ``` and enable **etherwake-nfqueue** in the **Network** sub-menu. It can either be selected as built-in (\*) or module (M), depending on your decision to include it into a firmware image or just build the *opkg* package for installation. Then you should be able to compile the package: ``` user@host:~/openwrt$ make package/etherwake-nfqueue/compile ``` The path of the resulting package depends on your selected *Target System*. In case of the Linksys WRT1200AC, it can be found here: ``` bin/packages/arm_cortex-a9_vfpv3/ethernfq/etherwake-nfqueue_2019-09-10-67e9d4ca-1_arm_cortex-a9_vfpv3.ipk ``` ## Installation One way to install the package is by simply copying it over to the device with *scp*: ``` user@host:~$ scp etherwake-nfqueue_2019-09-10-67e9d4ca-1_arm_cortex-a9_vfpv3.ipk root@gateway:~ ``` And then, install it on the device: ``` root@gateway:~# opkg install etherwake-nfqueue_2019-09-10-67e9d4ca-1_arm_cortex-a9_vfpv3.ipk ``` ## Configuration ### WoL Targets After a fresh installation, no target is configured. Targets are referred to as the hosts to wake up. Multiple targets can coexist. Targets can be configured with OpenWrt's UCI. For example, to add a target called **nas**, with MAC address **00:25:90:00:d5:fd**, which is reachable over the VLAN configured on **eth0.3**, issue this command sequence on your router: ``` uci add etherwake-nfqueue target uci set etherwake-nfqueue.@target[-1].name=nas uci set etherwake-nfqueue.@target[-1].mac=00:25:90:00:d5:fd uci set etherwake-nfqueue.@target[-1].interface=eth0.3 uci commit ``` For each target, one instance of **etherwake-nfqueue** will be started. Each instance should bind to a different *nfnetlink_queue*. A queue can be referenced by its queue number. Counting starts from 0, which is the default. To use a different queue, provide the **nfqueue_num** option. The following could have been added to the sequence above to use queue 1 instead of 0: ``` uci set etherwake-nfqueue.@target[-1].nfqueue_num=1 ``` The necessity of a queue number will probably become clear, when the iptables rules are configured in section [Setup firewall rules](#setup-firewall-rules). The full list of options for a target is: | Option | Required | Description | | ----------- | -------- | ------------------------------------------------ | | name | no | Name of the target, e.g. name=example | | mac | yes | MAC address of the host to wake up, e.g. mac=00:22:44:66:88:aa | | nfqueue_num | no | The queue number used for receiving filtered packets, default is nfqueue_num=0 | | interface | no | The interface used for sending the magic packet, default is interface=eth0 | | broadcast | no | Send magic packet to broadcast address, default is broadcast=off | | password | no | Set a password (required by some adapters), e.g. password=00:22:44:66:88:aa or 192.168.1.1 | | enabled | no | Optionally disable the target, default is enabled=true | After committing your changes, the settings are persisted to */etc/config/etherwake-nfqueue*. This is an illustrative example: ``` config etherwake-nfqueue 'setup' option sudo 'off' option debug 'off' config target option name 'nas' option mac '00:25:90:00:d5:fd' option interface 'eth0.3' config target option name 'xyz-board' option mac '00:25:90:00:d5:fc' option nfqueue_num '1' option enabled 'false' config target option name 'ip-camera' option mac '00:25:90:00:d5:fb' option nfqueue_num '2' option interface 'eth0.3' option broadcast 'on' option password '00:25:90:00:d5:fb' ``` When all target(s) are configured, restart the *etherwake-nfqueue* service: ``` /etc/init.d/etherwake-nfqueue restart ``` ### Setting up filters Without any firewall rules which tell the kernel to match and add packets to a *nfnetlink_queue*, **etherwake-nfqueue** will never send out a magic packet to wake its target. #### Prerequisites In order to let the *netfilter* framework of the kernel see the packets, they need to pass through the router. This is usually not the case when hosts are on the same subnet and don't require network layer routing. The data will only pass through the router's switch on the link layer. As a consequence, we can only use packets as a trigger which need to be routed or bridged by the router. Packets being forwarded between WAN and LAN are of that type. For other SOHO use cases, partitioning your network by means of subnets or VLANs might be necessary. The latter is often used to set up a DMZ. For VLANs: * There's a mini howto referring to the **LuCI Web Interface** *(Network -> Switch)* way of configuring VLANs: [How-To: Creating an additional virtual switch on a typical home router](https://openwrt.org/docs/guide-user/network/vlan/creating_virtual_switches) * The manual approach is documented here: [VLAN](https://openwrt.org/docs/guide-user/network/vlan/switch_configuration) Guides to setup a DMZ can be found here: * [Guide to set up DMZ via LUCI](https://forum.openwrt.org/t/guide-to-set-up-dmz-via-luci/21616) * [fw3 DMZ Configuration Using VLANs](https://openwrt.org/docs/guide-user/firewall/fw3_configurations/fw3_dmz) The physical switch layout is device specific. E.g. the layout for the Linksys WRT AC Series is documented [here](https://oldwiki.archive.openwrt.org/toh/linksys/wrt_ac_series#switch_layout). Using two LANs or VLANs with the same network address and bridging them again is a trick to setup a transparent (or bridging) firewall on the same subnet. This way, packets can be seen by *netfilter* on the router even if the packets are not routed. Unfortunately this doesn't help when the host which we want to wake up is offline, as the ARP requests for the destination IP address are not answered and thus the client trying to reach out to its destination will not send any *network layer* packets. We could use *arptables* instead to wake the host when someone requests its MAC address, but this would probably happen too often and no fine-grained control would be possible. As a workaround, it might be possible to configure a static ARP entry on your router (untested), e.g. with: ``` ip neigh add 192.168.0.10 lladdr 00:25:90:00:d5:fd nud permanent dev eth0.3 ``` Note that this requires the *ip-full* OpenWrt package to be installed. To make your firewall rules work with bridging, you need to install the *kmod-br-netfilter* package and add `net.bridge.bridge-nf-call-iptables=1` to */etc/sysctl.conf*. #### Setup firewall rules One way to setup custom firewall rules in OpenWrt is through its */etc/firewall.user* script. This file can also be edited by means of the **LuCI Web Interface** *(Network -> Firewall -> Custom Rules)*. The file is interpreted as a shell script, so we can simply use **iptables** to add our custom firewall rules. Notice the comment ``` # Internal uci firewall chains are flushed and recreated on reload, so # put custom rules into the root chains e.g. INPUT or FORWARD or into the # special user chains, e.g. input_wan_rule or postrouting_lan_rule. ``` Refer to [Packet flow](https://oldwiki.archive.openwrt.org/doc/uci/firewall#packet_flow) for usable chains. In the example below, the chains *forwarding_lan_rule* and *forwarding_wan_rule* are used. To inspect the rule sets of the different tables, one can use ``` iptables --list # default is --table filter iptables --table nat --list iptables --table mangle --list iptables --table raw --list # requires kmod-ipt-raw ``` The following is an example of what could be added to */etc/firewall.user*: ``` iptables --insert forwarding_lan_rule\ --protocol tcp --in-interface=br-lan --out-interface=eth0.3\ --destination 192.168.0.10 --destination-port 445\ --match conntrack --ctstate NEW\ --match limit --limit 3/hour --limit-burst 1\ --jump NFQUEUE --queue-num 0 --queue-bypass\ --match comment --comment "Wake up NAS on LAN SMB" iptables --insert forwarding_lan_rule\ --protocol tcp --in-interface=br-lan --out-interface=eth0.3\ --destination 192.168.0.11 --match multiport --destination-ports 515,54921,631\ --match conntrack --ctstate NEW\ --match limit --limit 3/hour --limit-burst 1\ --jump NFQUEUE --queue-num 0 --queue-bypass\ --match comment --comment "Wake up NAS on print request" iptables --insert forwarding_lan_rule\ --protocol udp --in-interface=br-lan --out-interface=eth0.3\ --destination 192.168.0.11 --destination-port 161\ --match conntrack --ctstate NEW\ --match limit --limit 3/hour --limit-burst 1\ --jump NFQUEUE --queue-num 0 --queue-bypass\ --match comment --comment "Wake up NAS on print request" iptables --insert forwarding_wan_rule\ --protocol tcp --in-interface=eth1.2 --out-interface=eth0.3\ --destination 192.168.0.10 --destination-port 22\ --match conntrack --ctstate NEW\ --match limit --limit 3/hour --limit-burst 1\ --jump NFQUEUE --queue-num 0 --queue-bypass\ --match comment --comment "Wake up NAS on WAN SSH" ``` In this example, packets are filtered based on the protocol, their input and output interfaces, their destination (IP address) and their destination port(s). The option `--match conntrack --ctstate NEW` only matches packets of a new connection and `--match limit --limit 3/hour --limit-burst 1` limits the amount of packets that are matched. The latter option roughly matches only one packet per 20 minutes. The intention here is to not be too intrusive and avoid sending a lot of magic packets. The `--jump NFQUEUE --queue-num 0` options tell the *netfilter* framework to enqueue a matching packet to the NFQUEUE number 0. In this example, all four rules send the matching packets into queue 0. The additional option `--queue-bypass` helps in the situation, when **etherwake-nfqueue** isn't running. Packets will then be handled as if the rule wasn't present. ## Disabling targets To disable targets, first find their index: ``` uci show etherwake-nfqueue ``` Then set its *enabled* option to false and restart the service. For index 0, it can be done like this: ``` uci set etherwake-nfqueue.@target[0].enabled=false /etc/init.d/etherwake-nfqueue restart ``` ## Troubleshooting ### Debug mode In order to see what's going on in syslog and get some debug output when starting the service, enable etherwake-nfqueue's debug mode: ``` uci set etherwake-nfqueue.setup.debug=on ``` In another user session tail the log: ``` logread -f ``` And then restart the service: ``` /etc/init.d/etherwake-nfqueue restart ``` ### Inspect netfilter To inspect the working of your firewall rules, you can print statistics of the chains you used, e.g.: ``` iptables --verbose --list forwarding_lan_rule ``` If you happen to have the *procps-ng-watch* package installed, you can watch them: ``` watch iptables --verbose --list forwarding_lan_rule ``` To see, if your queues are in place, use: ``` cat /proc/net/netfilter/nfnetlink_queue ``` ## Potential improvements * Add **LuCI Web Interface** configuration frontend for *targets* and *filter rules* * Add an option to set *nice* values for instances