etherwake-nfqueue: Add package etherwake-nfqueue
authorMister Benjamin <144dbspl@gmail.com>
Sat, 28 Sep 2019 20:20:39 +0000 (22:20 +0200)
committerMister Benjamin <144dbspl@gmail.com>
Sat, 28 Sep 2019 20:20:39 +0000 (22:20 +0200)
Signed-off-by: Mister Benjamin <144dbspl@gmail.com>
net/etherwake-nfqueue/Makefile [new file with mode: 0644]
net/etherwake-nfqueue/README.md [new file with mode: 0644]
net/etherwake-nfqueue/files/etherwake-nfqueue.config [new file with mode: 0644]
net/etherwake-nfqueue/files/etherwake-nfqueue.init [new file with mode: 0644]

diff --git a/net/etherwake-nfqueue/Makefile b/net/etherwake-nfqueue/Makefile
new file mode 100644 (file)
index 0000000..b72e786
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2019 Mister Benjamin <144dbspl@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=etherwake-nfqueue
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/mister-benjamin/etherwake-nfqueue.git
+PKG_SOURCE_DATE:=2019-09-28
+PKG_SOURCE_VERSION:=f71c269b58585e93575fa3e9fcc1793806fb3080
+PKG_MIRROR_HASH:=4960dc592abc4ca06504c92ca09fc736c678353df0dcc32d4081e17b137a9164
+
+PKG_MAINTAINER:=Mister Benjamin <144dbspl@gmail.com>
+PKG_LICENSE:=GPL-2.0+
+
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/cmake.mk
+
+define Package/etherwake-nfqueue
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libnetfilter-queue +iptables-mod-nfqueue
+  TITLE:=Wake up computers on netfilter match
+  URL:=https://github.com/mister-benjamin/etherwake-nfqueue
+endef
+
+define Package/etherwake-nfqueue/description
+ Fork of etherwake with additional support for sending WOL packets
+ when a router added a filtered packet to an NFQUEUE.
+endef
+
+define Package/etherwake-nfqueue/conffiles
+/etc/config/etherwake-nfqueue
+endef
+
+define Package/etherwake-nfqueue/install
+       $(INSTALL_DIR) $(1)/usr/bin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/etherwake-nfqueue $(1)/usr/bin/
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_CONF) files/$(PKG_NAME).config $(1)/etc/config/$(PKG_NAME)
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) files/$(PKG_NAME).init $(1)/etc/init.d/$(PKG_NAME)
+endef
+
+$(eval $(call BuildPackage,etherwake-nfqueue))
diff --git a/net/etherwake-nfqueue/README.md b/net/etherwake-nfqueue/README.md
new file mode 100644 (file)
index 0000000..b44ac9e
--- /dev/null
@@ -0,0 +1,378 @@
+# 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
diff --git a/net/etherwake-nfqueue/files/etherwake-nfqueue.config b/net/etherwake-nfqueue/files/etherwake-nfqueue.config
new file mode 100644 (file)
index 0000000..541bbe2
--- /dev/null
@@ -0,0 +1,21 @@
+config etherwake-nfqueue 'setup'
+       option sudo 'off'
+       option debug 'off'
+
+# You can add targets with uci:
+# # uci add etherwake-nfqueue target
+# Set a name for the target
+# # uci set etherwake-nfqueue.@target[-1].name=example
+# Set MAC address of the host to wake up
+# # uci set etherwake-nfqueue.@target[-1].mac=00:22:44:66:88:aa
+# Set the nfqueue num used for receiving filtered packets, defaults to 0
+# # uci set etherwake-nfqueue.@target[-1].nfqueue_num=0
+# Set the interface used for sending the magic packet, defaults to 'eth0'
+# # uci set etherwake-nfqueue.@target[-1].interface=eth0
+# Configure if it should be sent to broadcast address, defaults to off
+# # uci set etherwake-nfqueue.@target[-1].broadcast=off
+# Optionally provide a password (required by some adapters)
+# e.g. 00:22:44:66:88:aa or 192.168.1.1
+# # uci set etherwake-nfqueue.@target[-1].password=00:22:44:66:88:aa
+# Optionally disable the target, by default it is enabled
+# # uci set etherwake-nfqueue.@target[-1].enabled=false
diff --git a/net/etherwake-nfqueue/files/etherwake-nfqueue.init b/net/etherwake-nfqueue/files/etherwake-nfqueue.init
new file mode 100644 (file)
index 0000000..0be740d
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh /etc/rc.common
+#
+# Copyright (C) 2019 Mister Benjamin <144dbspl@gmail.com>
+
+NAME='etherwake-nfqueue'
+
+START=60
+USE_PROCD=1
+
+PROGRAM=${NAME}
+
+start_service()
+{
+    local value
+
+    config_load ${NAME}
+
+    config_get_bool value setup sudo 0
+    [ "${value}" -ne 0 ] && PROGRAM="sudo ${PROGRAM}"
+
+    config_get_bool value setup debug 0
+    if [ "${value}" -ne 0 ]; then
+        PROCD_DEBUG=1
+        append PROGRAM '-D'
+    fi
+
+    config_foreach start_instance target
+}
+
+start_instance()
+{
+    local section="$1"
+    local value name mac
+
+    config_get_bool value "${section}" enabled 1
+    [ "${value}" -ne 1 ] && return 0
+
+    config_get value "${section}" name
+    [ -z "${value}" ] && value="{section}"
+    name=${value}
+
+    config_get mac "${section}" mac
+    [ -z "${mac}" ] && {
+        echo "${initscript}: Target ${name} has no MAC address"
+        return 1
+    }
+
+    procd_open_instance ${name}
+    procd_set_param command ${PROGRAM}
+    procd_set_param respawn
+    procd_set_param stdout 1
+    procd_set_param stderr 1
+
+    config_get_bool value "${section}" broadcast 0
+    [ "${value}" -ne 0 ] && procd_append_param command -b
+
+    config_get value "${section}" interface
+    [ -n "${value}" ] && procd_append_param command -i "${value}"
+
+    config_get value "${section}" password
+    [ -n "${value}" ] && procd_append_param command -p "${value}"
+
+    config_get value "${section}" nfqueue_num 0
+    procd_append_param command -q "${value}"
+
+    procd_append_param command "${mac}"
+
+    procd_close_instance
+}