Running a DHCP server on WD My Cloud NAS

The WD My Cloud Pro PR2100 has an Intel Pentium N3710 quad-core 1.6 GHz processor and 4GB of DDR3 memory, which is a decent spec on which to run a NAS and some additional services. Having experienced issues with the built-in DHCP server on my Internet access provider’s router, I want to run the DHCP server for my LAN on the NAS instead.

The Busybox installation on the PR2100 includes the udhcpd server package, but the configuration and leases are wiped out each time the appliance is rebooted. To address this I’ve come up with a simple method to maintain persistence across reboots.

First create a new share on your storage which will hold your dhcpd config files, e.g. ‘dhcp’.

Next create your udhcpd.conf in the new share (/shares/dhcp) and specify the runtime options. I have provided an example below:

interface bond0
max_leases 100
remaining yes
auto_time 7200
lease_file /shares/dhcp/udhcpd.leases
pidfile /var/run/
opt dns
opt dns
opt domain local
opt router
opt subnet
opt lease 432000
static_lease 12:34:56:78:90:aa static-host-a
static_lease 12:34:56:78:90:ab static-host-b

To make this configuration persistent across reboots you’ll need to append some commands to the startup script of a system app. For this purpose I added the ‘Internal Backups’ app which is installed to /shares/Volume_1/Nas_Prog/InternalBackups

Edit the startup script for this app (/shares/Volume_1/Nas_Prog/InternalBackups/ and add these two lines:

touch /shares/dhcp/udhcpd.leases
/usr/sbin/udhcpd /shares/dhcp/udhcpd.conf

This will start udhcpd whenever the device is restarted and DHCP leases will remain persistent across system reboots.

To check the status of your leases you can ssh into your PR2100 (username is ‘sshd’) and use the dumpleases command. I use this command which sorts on IP address:

dumpleases -f /shares/dhcp/udhcpd.leases | tail +2 | sort -k 2

If you update the system app onto which you’ve piggy-backed the udhcpd startup commands then don’t forget to check the init script afterwards as you may need to add them again.

Gmail style ‘plus’ email aliases in Office365

It’s an often used feature of Gmail to append a ‘+’ (plus) to an email address to create an unlimited number of instant email aliases – see Gmail Blog for an explanation. I gather this is also a feature of, but the same does not apply for hosted domains on Office365. The same can however be achieved with a bit of configuration.

Go to Exchange Admin Centre > mail flow > rules and create a new rule as follows:

Create this rule… The sender is located… Outside the organization

and The recipient address matches… ^yourname\+[\w-]

(For example, if your usual email address is then the rule should match ^David\+[\w-]

Do the following… Redirect the message to… <select your user>

(The [\w-]+ regular expression will match one or more alphanumeric or hyphen characters).

Next choose the ‘external domains’ tab, select your domain and make sure that the domain type is set as an Internal Relay.

Now that this domain is an internal relay, we’ll need an extra rule to bounce email addressed to unknown recipients more gracefully (instead of looping internally).

Add this as your last mail flow rule:

Create this rule… The sender is located… Outside the organization

Do the following… Reject the message with the explanation… ‘User unknown’

Except if… The recipient is a member of… <select all the valid users>

You will now receive email addressed to in your regular inbox.

Disabling delivery and read receipts in Exchange Online

The default configuration for Office 365’s Exchange server is to automatically respond to requests for mail delivery reports. If like me you don’t want to divulge this information then here is what you need to do.

Follow these steps to block all forms of email delivery and read receipts …

Exchange Admin Centre > mail flow > remote domains > Default 
Untick 'Allow delivery reports' and 'Allow non-delivery reports'
Screenshot 2019-06-07 at 09.38.39.png
Next create four separate mail flow rules to remove these mail headers:
Exchange Admin Centre > mail flow > rules > +
Create a new rule > More options...

Apply this rule if... The Sender is located... Outside the organization
Do the following... Modify the message properties...
Remove a message header (paste a header as above)
You should end up with four rules like these:
Screenshot 2019-06-07 at 09.39.06.png
Those mail flow rules should strip out the headers and block read receipts before they reach a recipient’s mailbox, but just to be sure:
Outlook > Settings > View all Outlook settings > Email
Message handling > Read receipts > Never send a response
Screenshot 2019-06-07 at 10.01.42.png

New uses for old Dash buttons

I recently acquired a few Amazon Dash buttons and wondered if they might be repurposed to serve some useful purpose, other than ordering groceries.

I found this article by Ted Benson in which he describes how Dash buttons send an ARP probe after joining the WiFi network. By listening for these ARP probes (and their unique MAC addresses) you can trigger IFTTT Webhooks workflows, which turns the humble Amazon ordering tool into a customisable IoT button.

Bob Steinbeiser replied to Ted’s post with a clever Python script which sniffs ARP packets using a raw socket. Having played with Bob’s script I set about trying to make a few improvements. I’m a novice when it comes to Python though, so forgive my amateur code.

import socket
import struct
import binascii
import urllib2
import time

# Based on an original script by Bob Steinbeiser (
# Adapted to ignore duplicate presses and added support for multiple IFTTT triggers

# Use your own IFTTT Webhooks key here - see
ifttt_key = 'abc123'

# MAC addresses and their corresponding IFTTT Webhooks triggers
things = {
    'aabbccddeeff' : ['lights_off', 'sockets_off'],
    'a0b1c2d3e4f5' : ['test_1', 'test_2', 'test_3']


for macaddr in things:
    last_success[macaddr] = 0

rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))

while True:
    packet = rawSocket.recvfrom(2048)

    ethernet_header = packet[0][0:14]
    ethernet_detailed = struct.unpack('!6s6s2s', ethernet_header)

    arp_header = packet[0][14:42]
    arp_detailed = struct.unpack('2s2s1s1s2s6s4s6s4s', arp_header)

    # Skip non-ARP packets
    ethertype = ethernet_detailed[2]
    if ethertype != '\x08\x06':

    source_mac = binascii.hexlify(arp_detailed[5])

    time_now = int(time.time())

    # Is this a known 'thing' ?
    if source_mac in things:

        trigger_list = things[source_mac]

        # Prevent duplicate presses from being actioned (within 10 secs)
        if time_now > last_success[source_mac] + 10:
            # Supports multiple IFTTT Webhook triggers
            for trigger in trigger_list:

                print "Device " + source_mac + " has triggered " + trigger
                last_success[source_mac] = int(time.time())
                data = '{ "value1" : "' + source_mac + '", "value2" : "' + trigger + '" }'
                req = urllib2.Request('' + trigger + '/with/key/' + ifttt_key, data, {'Content-Type': 'application/json'})
                f = urllib2.urlopen(req)
                response =
                print response

             print "Ignoring repeated event for " + source_mac

        print "Ignoring unknown device " + source_mac

Note that this Python script doesn’t work on Mac OS, due to the lack of support for AF_PACKET sockets.

Sky Hub syslogging to Mac OS

The standard issue Sky Broadband SR102 ADSL router includes the capability to send syslog messages to a remote host.

Unfortunately the plucky little SR102 doesn’t send syslog messages in entirely the right format (checked using ‘syslog -F raw’):

[ASLMessageID 303320877] [Time 1463491448] [TimeNanoSec 0] [Level 2]
 [PID 4294967295] [UID 4294967294] [GID 4294967294] [ReadGID 80] [Host
 1] [Sender 2016-05-17T14] [Facility daemon] [Message 24:08.000Z
 skyhub.ihr syslog - - [skySDID@32666 mac="7C4CA5D9E148"
 sn="A502141D002081"]  Administrator login successful from IP: .]

You can however still use Mac OS’s syslog daemon to receive these messages, but first you’ll need to enable the socket listener:

cd /System/Library/LaunchDaemons
sudo /usr/libexec/PlistBuddy -c "add :Sockets:NetworkListener dict"
sudo /usr/libexec/PlistBuddy -c "add :Sockets:NetworkListener:SockServiceName string syslog"
sudo /usr/libexec/PlistBuddy -c "add :Sockets:NetworkListener:SockType string dgram"

To restart the syslog daemon:

sudo launchctl unload /System/Library/LaunchDaemons/
sudo launchctl load /System/Library/LaunchDaemons/

Next go into the Sky Hub web interface, click on the Security tab (default admin credentials are admin / sky), select Logs and then enter the IP address of your Mac in the Syslog server address.

You can check for Sky Hub syslog entries in /var/log/system.log

To filter out the Sky Hub messages into a separate log file, add these two lines to /etc/asl.conf and then restart the syslog daemon again:

# Sky SR102 broadband router saved to skyhub.log
? [S= Message skyhub.ihr ] file skyhub.log mode=0640 format=bsd rotate=seq compress all_max=50M

The query-action rule tells syslogd to match on the “skyhub.ihr” substring in the Message key and then save those entries to /var/log/skyhub.log. The options are for log file rotation, retaining up to 50MB of files.

Typical Sky Hub log entries will include connection retraining, web interface logins and NTP synchronisations.