Friday, 15 July 2022

Setting up mobile backup for my home broadband

As part of an interview for a Technical Product Manager job I had to create a video presentation how I would improve a product at home. I have chosen my home broadband and argued for enabling monitoring and mobile backup as an improvement. While I am monitoring my home broadband for quite some time I have always played with the idea to use my mobile data plan in case my fixed broadband is down.

I recently moved default gateway function to my monitoring Raspberry Pi with the help of a VLAN enabled switch - see my previous post about it. The mobile coverage in the electric room where my broadband modem installed is probably the weakest in the building so not an ideal place for a mobile backup solution. On the other hand upstairs at my working desk the mobile coverage is reasonable and I have my other Raspberry Pi that I use as my desktop PC usually. I also regularly charge my phone next to this Raspberry Pi which sparked the idea to extend USB tethering as a mobile backup solution for the entire home. For this I need to change the routing at both Raspberry Pi in case the fixed broadband is down so that all traffic is routed via USB tethering. For this I have found a failover script here that I have customised for my use case as follows on the Raspberry Pi next to my broadband modem:

jordana@pi4b2:~ $ nano failover.sh

#!/bin/bash


# Set defaults if not provided by environment

CHECK_DELAY=${CHECK_DELAY:-1}

CHECK_IP=${CHECK_IP:-8.8.8.8}

PRIMARY_IF=${PRIMARY_IF:-eth0.8}

PRIMARY_GW=${PRIMARY_GW:-192.168.0.1}

BACKUP_IF=${BACKUP_IF:-eth0}

BACKUP_GW=${BACKUP_GW:-192.168.0.12}


# Compare arg with current default gateway interface for route to healthcheck IP

gateway_if() {

  [[ "$1" = "$(ip route get "$CHECK_IP" | sed -rn 's/^.*dev ([^ ]*).*$/\1/p')" ]]

}


# Cycle healthcheck continuously with specified delay

while sleep "$CHECK_DELAY"

do

  # If healthcheck succeeds from primary interface

  if ping -I "$PRIMARY_IF" -c1 "$CHECK_IP" &>/dev/null

  then

    # Are we using the backup?

    if gateway_if "$BACKUP_IF"

    then # Switch to primary

      ip route delete default via "$BACKUP_GW" dev "$BACKUP_IF"

    fi

  # If healthcheck fails from primary interface

  else

    # Are we using the primary?

    if gateway_if "$PRIMARY_IF"

    then # Switch to backup

      ip route add default via "$BACKUP_GW" dev "$BACKUP_IF"

    fi

  fi

done


On my desk I also have a failover script running on the Raspberry Pi: 


jordana@dad-pi4g:~ $ nano failover.sh

#!/bin/bash


# Set defaults if not provided by environment

CHECK_DELAY=${CHECK_DELAY:-1}

CHECK_IP=${CHECK_IP:-8.8.8.8}

PRIMARY_IF=${PRIMARY_IF:-eth0}

PRIMARY_GW=${PRIMARY_GW:-192.168.0.1}

BACKUP_IF=${BACKUP_IF:-usb0}

BACKUP_GW=${BACKUP_GW:-192.168.0.1}

EMAIL=${EMAIL:-jordan.arpad@gmail.com}


# Compare arg with current default gateway interface for route to healthcheck IP

gateway_if() {

  [[ "$1" = "$(ip route get "$CHECK_IP" | sed -rn 's/^.*dev ([^ ]*).*$/\1/p')" ]]

}


switch_to_primary() {

  ip route delete default via "$PRIMARY_GW" dev "$PRIMARY_IF"

  ip route add default via "$PRIMARY_GW" dev "$PRIMARY_IF"

  date | mail -s "$HOSTNAME switched to primary" "$EMAIL"

}


switch_to_backup() {

  ip route delete default via "$PRIMARY_GW" dev "$PRIMARY_IF"

  ip route add default via "$PRIMARY_GW" dev "$PRIMARY_IF" metric 5000

  date | mail -s "$HOSTNAME switched to backup" "$EMAIL"

}


# Cycle healthcheck continuously with specified delay

while sleep "$CHECK_DELAY"

do

  # If healthcheck succeeds from primary interface

  if ping -I "$PRIMARY_IF" -c1 "$CHECK_IP" &>/dev/null

  then

    # Are we using the backup?

    if gateway_if "$BACKUP_IF"

    then switch_to_primary

    fi

  # If healthcheck fails from primary interface

  else

    sleep "$CHECK_DELAY"

    # If healthcheck succeeds from primary interface

    if ping -I "$PRIMARY_IF" -c1 "$CHECK_IP" &>/dev/null

    then

      # Are we using the backup?

      if gateway_if "$BACKUP_IF"

      then switch_to_primary

      fi

    # If healthcheck fails from primary interface AGAIN

    else

      # Are we using the primary?

      if gateway_if "$PRIMARY_IF"

      then switch_to_backup

      fi

    fi

  fi

done

I added routing and NAT to usb0 on the desktop Raspberry Pi also and whenever I have my phone connected with USB tethering to the mobile network the redundancy switching is working like a charm back and forth :) So I made these scripts running @reboot from crontab and configured notification emails from my desktop Raspberry.


UPDATE

I added email notification to the script as per above after installing ssmtp and mailutils and configured as follows. Please note that this only works with App Password added to your Google account so use it with care, at your own risk and consider creating a separate Google account for this purpose.

jordana@dad-pi4g:~ $ sudo cat /etc/ssmtp/ssmtp.conf
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=

# The place where the mail goes. The actual machine name is required no 
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=smtp.gmail.com:587

# Where will the mail seem to come from?
rewriteDomain=

# The full hostname
hostname=dad-pi4g

# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
#FromLineOverride=YES

AuthUser=jordan.arpad73@gmail.com
AuthPass=
UseSTARTTLS=YES

Thursday, 14 July 2022

Moving NAT to Raspberry

In an attempt to control even more functions of my home broadband I have decided to use my monitoring Raspberry Pi to execute the NAT function also. For this, I had to have two Ethernet interfaces connected to the monitoring Raspberry Pi and also move all connections currently using the built-in switch to my provider router to a switch behind the monitoring Raspberry Pi executing the NAT function. I could use a USB Ethernet adapter, for example the one I had lying around from my extra Chromecast that Google have send for free with the Stadia controller. But I still needed an extra switch and as a prime day deal I have found this VLAN enabled switch on sale:

https://amzn.eu/53hbzq4

This solves both issues, providing multiple Ethernet interfaces attached to the Raspberry Pi with an 802.1q trunk and also accommodation for the connections previously on the provider router built-in switch.

Enabling a VLAN interface on the Raspberry Pi was straigthforward:

jordana@pi4b2:~ $ sudo apt install vlan

jordana@pi4b2:~ $ sudo nano /etc/network/interfaces.d/vlans

auto eth0.8

iface eth0.8 inet manual

  vlan-raw-device eth0

The corresponding VLAN configuration on the switch is as follows:


Raspberry Pi is connected to port 1 and an Ethernet port on the provider router to port 8.

I changed the provider router to modem mode and moved the default gateway address 192.168.0.1/24 of my home LAN to eth0 on the Raspberry Pi.

jordana@pi4b2:~ $ sudo nano /etc/dhcpcd.conf

interface eth0

static ip_address=192.168.0.1/24

I also had to change the NAT rule as follows (updated with rule to drop connection request from eth0.8):

jordana@pi4b2:~ $ sudo iptables -t nat -I POSTROUTING -o eth0.8 -j MASQUERADE
jordana@pi4b2:~ $ sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED -i eth0.8 -p tcp -j ACCEPT
jordana@pi4b2:~ $ sudo iptables -A INPUT -i eth0.8 -p tcp -j DROP

jordana@pi4b2:~ $ sudo iptables-save -f /etc/iptables.rules

Saturday, 12 June 2021

[Updated] Managing apt and pihole updates with ansible

I have a couple of Raspberry Pi to keep apt and pihole updated.

pi@dad-pi4g:~ $ sudo apt install ansible
pi@dad-pi4g:~ $ sudo nano /etc/ansible/hosts
[pi]
pi0
pi0w
pi1b
pi4b2
dad-pi4g
pi@dad-pi4g:~ $ nano apt.yml 
---
  - hosts: pi
    tasks:
      - become: yes
        apt:
          force_apt_get: yes
          update_cache: yes
          name: "*"
          state: latest
  - hosts: pi1b
    tasks:
      - name: update pihole
        command: "pihole -up"
pi@dad-pi4g:~ $ ansible-playbook apt.yml
pi@dad-pi4g:~ $ ansible-playbook apt.yml 

PLAY [pi] ************************************************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************************************
ok: [dad-pi4g]
ok: [pi4b2]
ok: [pi0w]
ok: [pi1b]
ok: [pi0]

TASK [apt] ***********************************************************************************************************************************************************************************
ok: [dad-pi4g]
ok: [pi4b2]
ok: [pi0w]
ok: [pi1b]
ok: [pi0]

PLAY [pi1b] **********************************************************************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************************************************************
ok: [pi1b]

TASK [update pihole] *************************************************************************************************************************************************************************
changed: [pi1b]

PLAY RECAP ***********************************************************************************************************************************************************************************
dad-pi4g                   : ok=2    changed=0    unreachable=0    failed=0   
pi0                        : ok=2    changed=0    unreachable=0    failed=0   
pi0w                       : ok=2    changed=0    unreachable=0    failed=0   
pi1b                       : ok=4    changed=1    unreachable=0    failed=0   
pi4b2                      : ok=2    changed=0    unreachable=0    failed=0   

UPDATE

To keep track of changes I created my first git repository for this project :)

https://github.com/jordanarpad/ansible-update

UPDATE 2

As moving from Chromium OS to Raspberry Pi OS on my pi4g there had to be some changes made to git repository. I have used git add and git commit before git push to update the repository. I had to create a personal access token for the later.

Sunday, 6 June 2021

Three elegant ways to access Synology from Raspberry

We have just come back from a long outstanding holiday in Wales, and we wanted to show the pictures we took on various devices to our friends on the big TV. As we have a Synology NAS nicknamed "tera", we decided to upload pictures on there. The basic infrastructure has been in place as I already had a DHCP reservation on the dnsmasq built into pi-hole for the Synology NAS. 

The first way to access Synology is via its web console: https://tera:5000/, and I use this regularly for management purposes. It provides files services also for upload and download.

The second way is to use Connect to Server... function in the Go menu of File Manager in Raspberry Pi OS. Since I use my Synology NAS as an iperf3 server, I also had the relevant ssh public keys copied over from my dad-pi4g to Synology. All I had to do is to add my private keys for the ssh-agent to use by:

pi@dad-pi4g:~ $ ssh-add .ssh/id_rsa
Identity added: .ssh/id_rsa (pi@dad-pi4g)

Adding this connection created a link in File Manager that shows up permanently every time I open it.

The third way is via Midnight Commander that helps to move multiple files over more easily.

Sunday, 16 May 2021

Web Content Filtering with OpenDNS

My friend's family has been the victim of a fraud attempt utilizing a malicious website, and neither police nor the operator promised an attempt to take the site down.  Also, I moved my broadband connection back to Virgin Media recently. Still, the WebSafe service Virgin Media includes in their standard broadband offering is not effective in my home network as I use pi-hole with Google upstream DNS.

For the above reasons, I decided to try OpenDNS as upstream DNS for my pi-hole. I have set up an account with OpenDNS and added my home network with dynamic DNS. To keep dynamic IP updated, I installed ddclient on my good old Raspberry Pi 1b hosting pi-hole service also, but I got FAILED messages in the log for the update.

May 16 11:48:23 pi1b ddclient[2018]: WARNING:  file /var/cache/ddclient/ddclient.cache, line 3: Invalid Value for keyword 'ip' = ''
May 16 11:48:25 pi1b ddclient[2020]: FAILED:   updating Home: authorization failed (HTTP/1.0 401 Unauthorized
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    date: Sun, 16 May 2021 10:48:24 GMT
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    server: opendns
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    www-authenticate: Basic realm="RESTRICTED"
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    content-length: 7
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    content-type: text/html; charset=UTF-8
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    x-envoy-upstream-service-time: 57
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    x-xss-protection: 1; mode=block
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    x-ingress-point: lon
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    connection: close
May 16 11:48:25 pi1b ddclient[2020]: FAILED:
May 16 11:48:25 pi1b ddclient[2020]: FAILED:    badauth)

I opened a support case with OpenDNS but continued free of charge OpenDNS Family Shield service for now with Low filtering level. It gives a similar service to Virgin Media WebSafe. I will continue to look for ways to get the malicious website that my friend's family has fallen victim to being covered by the Phishing Protection of this free of charge OpenDNS Family Shield service.

-- UPDATE --

Browsing OpenDNS forums, I realised that I had character > in my password, and this character has special HTML encoding. Removing this character from my password made the update a SUCCESS:

May 16 12:53:42 pi1b ddclient[2702]: SUCCESS:  updating Home: good: IP address set to x.x.x.x

Unfortunately, registration to PhishTank is temporarily disabled, so I can not report the malicious website yet, but I will regularly check back.

-- UPDATE 2 --

Posting this issue on LinkedIn brought the malicious website issue to a resolution. A former colleague of mine pointed me to the hosting provider scam reporting web form. Within 24 hours the hosting provider has taken down the malicious site - well done weebly.com!

Another former colleague of mine called my attention again to the privacy benefits of using unbound, a recursive DNS resolver instead of an upstream DNS provider so I give it another try based on this guide.

Saturday, 17 April 2021

MTU issue with Zerotier

Just for the record, I had some issues using Zerotier between UK and US. For some reason, I could ping through with default packet size but ssh did not work. Once I changed MTU on UK side as follows it was working stable.

pi@pi0w:~ $ sudo nano /etc/dhcpcd.conf
interface wlan0
static interface_mtu=1200

Thursday, 1 April 2021

Exploring software defined radios

When last season Premier League restarted behind closed gates some games were broadcasted on Pick (a free to air Sky channel) paralell to paid streaming so I built a DVB-T hat on a Raspberry Pi Zero W. This was great fun running a small TV headend able to stream BBC One, BBC Two, iTV, Channel 4 and Channel 5 simultaneously, all in HD quality to Kodi installed on any device. But with the cease of free to air games I realised that watching TV on the corresponding apps (BBC iPlayer, iTV Hub, etc.) is actually even more convenient and does not disturb my daugther as reception was only adequate from her window upstairs.
Already back then I read about software defined radios (SDR) but unfortunately the DVB-T hat I got has a Sony CXD2880 tuner that only supports DVB-T/T2.
One of my friends told me he had a lot of fun with SDR during lockdown so I decided to buy a Realtek RTL2832U based USB dongle and plugged it to an unused Raspberry Pi 4B from the drawer.

pi@pi4b2:~ $ lsusb
Bus 001 Device 035: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T

While DVB-T/T2 driver is loaded as default, there are plenty of other bands that can be demodulated as the underlying chip supports a test mode giving direct access to IQ stream output from the tuner. To get access to the other bands, first we need to blacklist the DVB driver:

pi@pi4b2:~ $ sudo nano /etc/modprobe.d/blacklist-dvb.conf
blacklist dvb_usb_rtl28xxu

After reboot we can install rtl-sdr package that is supported in Raspberry Pi OS:

pi@pi4b2:~ $ sudo apt install rtl-sdr
pi@pi4b2:~ $ rtl_test -t
Found 1 device(s):
  0:  Realtek, RTL2838UHIDIR, SN: 00000001

Using device 0: Generic RTL2832U OEM
Found Rafael Micro R820T tuner
Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 
[R82XX] PLL not locked!
Sampling at 2048000 S/s.
No E4000 tuner found, aborting.

Now I was ready to join to an ADS-B community and start sharing. I picked flightradar24 and installed their service with:

pi@pi4b2:~ $ sudo bash -c "$(wget -O - https://repo-feed.flightradar24.com/install_fr24_rpi.sh)"
pi@pi4b2:~ $ fr24feed-status 
[ ok ] FR24 Feeder/Decoder Process: running.
[ ok ] FR24 Stats Timestamp: 2021-04-01 10:46:26.
[ ok ] FR24 Link: connected [UDP].
[ ok ] FR24 Radar: T-EGMD67.
[ ok ] FR24 Tracked AC: 19.
[ ok ] Receiver: connected (16814 MSGS/0 SYNC).
[ ok ] FR24 MLAT: ok [UDP].
[ ok ] FR24 MLAT AC seen: 19.

It runs quite nicely now with 500-900 aircrafts seen in a day. This gives me access to the business plan of flightradar24.com (for all its worth) and my contribution can be viewed online on flightradar24.com as some nice aggregated statistics graphs or more details on actual aircrafts seen locally on port 8754.

UPDATE

I kept having disconnected USB dongle issues. Some error messages in /etc/dmesg suggested powering issues although I was using the official Raspberry Pi power supply. I gave this USB-C hub with power charging input a try:
https://smile.amazon.co.uk/gp/product/B08KW2MCK2/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1

In order to use the USB power input of the Raspberry Pi in OTG mode I had to add this line to the boot config file:
pi@pi4b2:~ $ sudo nano /boot/config.txt
otg_mode=1