Sorting by

zorruno wikki: Edgouter Firewall Control over MQTT

Edgouter Firewall Control over MQTT


2021-06-15 V0 - zorruno - Started Doc
2022-22-15 V1 - zorruno - Tidyup and full documentation


Use of MQTT & mqcontrol to block devices from a network on command, via an Edgerouter X router.


This came out of a discussion with a friend that they 'block' their kids devices when they need rooms tidied etc with various apps. I'm not huge on spyware and controlling children via nanny apps (and especially ones that are cloud or vendor based), but we do have the occasional issue of a child using their device into the wee hours when not checked.

I thought a good way to do this was via firewall rules, controlled via the MQTT service. I can block based on MAC address of device, which isn't perfect, however I monitor devices that connect without an approved MAC. Also, note that on many devices these days (eg Apple devices) you need to turn of the random generation of MAC addresses (their privacy mode)

Docker, mqcontrol and S6

Mqcontrol is a a useful tool to run scripts when MQTT values change. It is a script needs to run as a daemon, and the S6 overlay for docker is a great way of taking the had work or supervising scripts that need to run, and keep running. I could have used the mqcontrol docker container (from albertnis github) but used plain alpine and added the S6 overlay, then pushed the mqcontrol binary and other items to the image.

FROM alpine:3.12.0 AS s6-alpine

# Build the S6 Overlay Stuff

ADD${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
#ENTRYPOINT ["/init"]

# Build and some of image configuration
RUN apk upgrade --update --no-cache
RUN apk add --no-cache openssh

# Authorize SSH Host
RUN mkdir -p /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan > /root/.ssh/known_hosts

# Move app components into container
RUN mkdir -p /app
#COPY ./app/ /app/
#RUN chmod +x /app/
COPY ./app/mqcontrol /app/mqcontrol
RUN chmod +x /app/mqcontrol
COPY ./app/automated_rules_key /app/automated_rules_key
RUN chmod 600 /app/automated_rules_key

#Copy all the scripts into the services directory for S6
COPY ./app/scripts/ /etc/services.d/
RUN chmod -R +x /etc/services.d/

# Init
ENTRYPOINT [ "/init" ]

version: '3.3'
        build: .
            - "/dockervolumes/mqcontrol-scripts/data:/data"
            - "/etc/localtime:/etc/localtime:ro"
            - "/etc/timezone:/etc/timezone:ro"
        container_name: mqcontrol-scripts
        hostname: mqcontrol-scripts
        restart: unless-stopped

Mqcontrol control scripts to run with S6

I ran a bunch of scripts that were controlled by the S6 supervisor. The simplest way to do this is to pop a script in /etc/services.d/ , and in a subfolder under that. Call the script "run", and make it executable. You can see by the dockerfile above, I store all my scripts in ./app/scripts (in subfolders), and on build it moves them to the right place. My structure for the app directory is this:

├── automated_rules_key
├── mqcontrol
├── mqcontrol_0.4.1_linux_amd64
└── scripts
	├── mqc-block-kids-ipadmini
	│   └── run
	├── mqc-block-kids-iphone7
	│   └── run
	├── mqc-block-kids-macbook
	│   └── run
	├── mqc-unblock-kids-ipadmini
	│   └── run
	├── mqc-unblock-kids-iphone7
	│   └── run
	└── mqc-unblock-kids-macbook
		└── run

Mqcontrol Script examples

I won't go into the Mqcontrol format too much, but essentially this script is activated when the topic commands/firewall/block-mollie-iphone7 on the MQTT server is written to. The action is to SSH into the Edgerouter (using the private key). I have more info on mqcontol here

Blocking Script for one device, saved as app/scripts/mqc-block-kids-iphone7
/app/mqcontrol -i mqc-block-kids-iphone7 -c "ssh -l automated_rules -i /app/automated_rules_key /config/scripts/block-kids-iphone7" -h -t commands/firewall/block-kids-iphone7

Blocking Script for one device, saved as app/scripts/mqc-block-kids-iphone7
/app/mqcontrol -i mqc-unblock-kids-iphone7 -c "ssh -l automated_rules -i /app/automated_rules_key /config/scripts/unblock-kids-iphone7" -h -t commands/firewall/unblock-kids-iphone7

I could have easily made one script to control all devices, but I wanted to separate them in case I wanted individual control. I also found that running scripts on the router can be a bit slow at times, so I allow for this later in Node Red, but delaying each script action slightly.

Edgerouter Firewall setup

The above is all you need for running daemon scripts in a docker container, in this case a number of instances of mqcontrol.

We now need to set up the actual firewall on the Edgerouter to a default state, for each device we are going to control.

We can do that with the Edgerouter GUI. In the Firewall, if you don't already have a WAN_OUT section, create one (on my case, the interface is pppoe/out). We can then make a number of rules under this, one for each device we with to control.

EDIT the ruleset for WAN_OUT and add a rule for a device. Each will be numbered, and I'll use the example of Rule 2. All you need to change is below, and just under the BASIC and SOURCE tabs.

-- Give it a Description, (eg Drop access to Kid's Iphone7)
-- Enable the tick box
-- Choose action 'Accept'
-- Choose Protocol 'All Protocols"

-- Add the MAC Address of the device eg "02:df:76:b9:b7:1c"

Edgerouter firewall setup

Edgerouter scripts

Now we need some scripts on the router (that we are calling via ssh from mqcontrol) to do the firewall modification. Firstly, you have to be able to able to shell into the edgerouter and scripts live in /config/scripts. A script for the device control looks like this. Note I cam using rule 2, to match the firewall settings above:

Blocking script for one device (saved on the router as /config/scripts/block-kids-iphone7
$cfg begin
$cfg set firewall name WAN_OUT rule 2 action drop
$cfg commit
logger -s "Blocking: Kids Iphone7 Blocked"
exit 0

I also needed an unblocking script (saved on the router as /config/scripts/unblock-kids-iphone7
$cfg begin
$cfg set firewall name WAN_OUT rule 2 action accept
$cfg commit
logger -s "Blocking: Kids Iphone7 Unblocked"
exit 0

Control and Automation

With all the above, now there is a setup where if a topic on the MQTT is written to, the firewall will be controlled.

A write to commands/firewall/block-kids-iphone7 will run the firewall script to drop packets for that device's MAC address.
A write to commands/firewall/un block-kids-iphone7 will run the firewall script to accept packets for that device's MAC address.

There are now plenty of ways to automate this, eg with a wall switch, timers to allow use when chores are done etc using tools such as home assistant, node red etc.

Node Red example

This is my setup I put in place (initially - as I suspect there will be tweaks. It allows
-- Toggle action from a phone or touchscreen to block/unblock all devices
-- Toggle button to allow a '2 Hour' use of devices, and another to deny device internet access for 2 hours.
-- A scheduler that can be enable and disabled via MQTT. This allows blocking and unblocking (once of each per day) device internet access. The start/end time can be displayed and written to via MQTT.

node red firewall flow

Last edited by ZorrUno
Tue, 22 Mar 2022 04:31 UTC [diff]