Tuesday, 25 April 2023

Another workaround for ssh login issue over zerotier

 From a hotel room during a business trip I have experienced again that ssh over zerotier stuck at some initialization phase:

jordana@penguin:~$ ssh -v ubuntu@oracle.zeronsd
OpenSSH_8.4p1 Debian-5+deb11u1, OpenSSL 1.1.1n  15 Mar 2022
debug1: Reading configuration data /etc/ssh/ssh_config
...
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY

I suspect this has something to do with dropped packets again due to MTU limitations over zerotier tunnel as ssh into public IP directly works OK. To workaround this time I changed this line in ssh config:

jordana@penguin:~$ sudo nano /etc/ssh/ssh_config
   MACs hmac-sha2-256

While this made ssh work from terminal directly but ansible still could not connect.

Saturday, 4 March 2023

Running ansible apt via ZeroTier from penguin on Chromebook aka Crostini

As more traditional daily home work kicked in, I recently started to use a Chromebook and a Windows desktop so the Raspberry Pi 4 has lost its place on my desk. In order to keep all my Linux hosts updated with ansible apt even on the go, I installed ZeroTier on all my Linux hosts. To use hostnames instead of IP address in my ZeroTier network I maintain local DNS entries in .zt domain on my pi.hole running on my good old Raspberry Pi 1b. In order to use this DNS server on Crostini for .zt domain I installed dnsmasq on it and configured the IP address of Raspberry Pi 1b on the ZeroTier network as follows:

jordana@penguin:~$ sudo nano /etc/dnsmasq.conf
server=/zt/192.168.193.1 

To make sure this is used every time Crostini boots I uncommented this line from dhclient:

jordana@penguin:~$ sudo nano /etc/dhcp/dhclient.conf
prepend domain-name-servers 127.0.0.1;

To access admin interface on pi.hole I installed Firefox ESR from apt on Crostini as the integration into the desktop is amazing. Installing RealVNC Viewer was also reasonably straightforward on Chromebook. After downloading the deb package an Install with Linux has popped up for right-click in the Files application. This makes signing into RealVNC with the servers running on all my Raspberry Pi somewhat redundant and the limit of 5 computers coming with RealVNC Home license easily expandable.

UPDATE

Finally I moved away from double administration of names by using zeronsd based on this quick guide:

ZeroNSD Quickstart

As I have only found x86/amd64 releases in the official repo I have used a t2.micro on AWS for this service as it is eligible in the Free Tier.

Please note that in order for dnsmasq and zeronsd to coexist on this AWS machine we need the following configurations:

admin@ip-172-31-8-100:~$ sudo nano /etc/dhcp/dhclient.conf
prepend domain-name-servers 127.0.0.1;
admin@ip-172-31-8-100:~$ sudo nano /etc/dnsmasq.conf
server=/zeronsd/192.168.193.10
interface=lo
bind-interfaces

Please note that such configuration achieves per interface DNS setting. This is what zerotier-systemd-manager from the above ZeroNSD quick install suppose to do but usually fails due to most hosts are not using systemd-networkd and resolvconf for all other interfaces. Hence the installation of zerotier-systemd-manager can be skipped from the above quick guide with such configuration.

UPDATE 2

It turned out that after one year AWS charges even for a t2.micro so I moved zeronsd to my chromebook as I only use it for ansible. While this is not ideal as my chromebook is sleeping most of the time, I could not compile zeronsd on my good old Raspberry Pi 1b whatever I tried. I was so desparate that I tried tailscale instead and with that Magic DNS works out of the platform without the need to install extra components. This made me thinking hard about migrating to tailscale which BTW available on my Synology NAS Package Center and installed on latest quadra image by default.

UPDATE 3

Just for the record it realised that tailscale free plan limits the number of subnets to one while Zerotier poses no limit on subnets only on 25 nodes in its free plan so I stick to Zerotier.

UPDATE 4

On Coronation Day 6 May 2023, I have successfully built latest zeronsd 0.5.2 from git on Raspberry Pi 4 running Raspberry Pi OS 64 bit using the latest cargo 1.69.0 with these 3 commands:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
sudo apt install librust-openssl-dev
cargo install --git https://github.com/zerotier/zeronsd --branch main

Unfortunately with default config zeronsd service could start successfully at first attempt because could not reach my.zerotier.com. I had to add a longer restart timeout to come up properly.

jordana@pi4g:~ $ sudo nano /lib/systemd/system/zeronsd-xxxxxxxxxxxxxxxxx.service
[Service]
RestartSec=10

UPDATE 5

Finally I could successfully build on Raspberry Pi 1 Model B with 512M RAM by increasing swap memory to 512M based on this article:

https://pimylifeup.com/raspberry-pi-swap-file/

Not sure if this is needed but I also added install option to run only 1 job at a time:

cargo install --git https://github.com/zerotier/zeronsd --branch main --jobs 1

Please note the install takes nearly 10 hours on an otherwise quite system so plan carefully ahead.

As it turned out there is no need for changing the swap size in case Raspberry Pi OS lite is used.

UPDATE 6

In order to run pi-hole with zeronsd on the same host you have to limit pi-hole to bind on physical interface only. 

UPDATE 7

As this post is originally started off due to me moving to ARM based Chromebook let me keep here a link for Raspberry Pi Imager that can be installed on it.

Monday, 12 December 2022

Connecting my friend back home with Quadra

The unfortunate prolonged shortage of Raspberry Pi devices made me propose my friend to build Quadra from inovato on T95 mini available on amazon. It uses Network Manager so the policy routing configuration to connect back home is slightly different:

quadra@inovato:~$ nmcli connection show
NAME               UUID          TYPE     DEVICE
Wired connection 1 02e96ab3-xxxx ethernet eth0
quadra@inovato:~$ nmcli connection modify 02e96ab3-xxxx +ipv4.addresses 192.168.2.1/24
quadra@inovato:~$ nmcli connection modify 02e96ab3-xxx ipv4.routing-rules "priority 1 from 192.168.2.0/24 table 1"
quadra@inovato:~$ nmcli connection modify 02e96ab3-xxx ipv4.routes "192.168.2.0/24 192.168.2.1 table=1"
quadra@inovato:~$ nmcli connection modify 02e96ab3-xxx connection.autoconnect yes
quadra@inovato:~$ nmcli connection up 02e96ab3-xxx
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/6)
quadra@inovato:~$ sudo nmcli connection reload

I have struggled to configure static policy route with nmcli on zerotier interface because uuid of zerotier interface kept changing at every reboot. I ended up configuring NetworkManager dispatcher.d script as follows:

quadra@inovato:~$ sudo nano /etc/NetworkManager/dispatcher.d/10-ztrfyktzr7-up
#!/bin/bash
if [ "$1" = "ztrfyktzr7" ] && [ "$2" = "up" ]; then
  sudo /sbin/ip route add default via 192.168.191.3 table 1
fi
quadra@inovato:~$ sudo chmod 755 /etc/NetworkManager/dispatcher.d/10-ztrfyktzr7-up

To distribute destination route 192.168.2.0/24 via 192.168.191.2 I used zerotier web console manage route capability.

On both ends I enabled ipv4 routing:

quadra@inovato:~$ sudo nano /etc/sysctl.conf
net.ipv4.ip_forward=1

Finally, I configured masquerade on quadra back home. Please note the first rule is to ensure zerotier-cli can access zerotier service locally.

quadra@inovato:~$ sudo iptables -t nat -I POSTROUTING -o lo -j ACCEPT
quadra@inovato:~$ sudo iptables -t nat -I POSTROUTING -j MASQUERADE
quadra@inovato:~$ sudo iptables-save -f /etc/iptables.rules
quadra@inovato:~$ sudo nano /etc/rc.local
iptables-restore /etc/iptables.rules

UPDATE: I used some inspiration from forum.inovato.com to enable wifi access point.

https://forum.inovato.com/post/setting-up-wifi-access-point-on-t95-max-box-12520455?pid=1334656619


Monday, 31 October 2022

Connecting back to my home LAN/WAN from remote country unknown Wifi

I am preparing for a presentation in a remote country unknown Wifi environment where I need to demonstrate a Wifi capable unit that can not run VPN natively but requires a connection back to my home LAN/WAN environment.

This is more challenging then what I described in my previous blog detailing how do I connect back with my parents.

Connecting with my parents

Firstly, I will need 2 Wifi interfaces here: one in client mode that connects to the unknown foreign Wifi and another in AP mode that enables Wifi connection from the unit that I need to demonstrate.

I had this Wifi USB hub in my drawer for a long time waiting for its use case:

Wifi USB hub from Pi Hut 

It took me a while to make it work with legacy wext driver option configured for wpa_supplicant. Details are in this forum post:

RTL8188EU configuration 

Unfortunately it turned out that its throughput performance is only 3-4 Mbps that is so poor that my demonstration unit complains about it.

Fortunately, I have a unit from both generations of Raspberry Pi Zero (2) W providing me two Wifi adapters but I would need to connect them somehow. I played with the idea of connecting two computers with USB back to back for a long time. As hostapd keeps disconnecting on Raspberry Pi Zero W, I use Raspberry Pi Zero 2 W at home to connect to my parents LAN/WAN by means of an Ethernet enabled Chromecast power supply hence I wanted to keep its USB configuration intact. So this is how I configured OTG driver on Raspberry Pi Zero W:

jordana@pi0w:~ $ sudo nano /boot/config.txt
dtoverlay=dwc2
jordana@pi0w:~ $ sudo nano /boot/cmdline.txt
modules-load=dwc2,g_ether

This has made usb0 interface appear on Raspberry Pi Zero W. The cable I have found working is an ordinary micro USB cable with an OTG adapter on the Raspberry Pi Zero 2 W side. This has not only provided power either way but also changed NO-CARRIER to BROADCAST on the usb0 interface on the Raspberry Pi Zero W side and created a usb0 interface on the Raspberry Pi Zero 2 W side also.

I also had to add DHCP configuration on the Raspberry Pi Zero W side:

jordana@pi0w:~ $ sudo nano /etc/dnsmasq.conf
interface=usb0
dhcp-range=192.168.10.2,192.168.10.20,255.255.255.0,24h
 

Finally, I enabled routing and masquerading on Raspberry Pi Zero W side and hostapd, dnsmasq and source based policy routing into zerotier VPN on the Raspberry Pi Zero 2 W side as described in my previous blog post about connecting to my parents.

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.