The Pico Pedal

One of the projects that I have been meaning to work on for a while is a foot pedal to use with discord, which for those that are not aware is a text and voice communications application. Most of the time when I am using discord for voice communications, I don't really want to be using a push-to-talk key to be able to talk to people, mostly because I'm usually busy pushing other keys on the keyboard. My original plan was to use an arduino, but then I found out about the RaspberryPi Pico.

The appealing thing to me about the Pico is that it can run python code. So I ordered a couple of Picos, snagged a generic footswitch off of amazon, and waited for the parts to arrive.

Since I don't have anything to use as a case currently, I soldered the two wires directly to the board, and then used some string through the mounting holes to secure the board to the end of the cord from the pedal.

/images/raspberrypypico/picopedal_resize.jpg

The code was pretty simple after reading the documentation for the adafruit_hid library. Whenever I use the footswitch, it sends the keypress for the menu, or application, key.

import time
import digitalio
import board
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard import Keycode

keyboard = Keyboard(usb_hid.devices)
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT

led.value = False

foot_switch = digitalio.DigitalInOut(board.GP0)
foot_switch.direction = digitalio.Direction.INPUT
foot_switch.pull = digitalio.Pull.DOWN

while True:
    if foot_switch.value:
    led.value = True
    keyboard.press(Keycode.APPLICATION)
else:
    keyboard.release(Keycode.APPLICATION)
    led.value = False
time.sleep(0.1)

Projects, just not visible

I haven't been spending much time out in the wood shop lately. I still have lots of ideas, lots of goals, just have not had the drive to get out there. Part of that is due to current world events, for those in the future, COVID-19 sucks, the delta variant more so. Part of the lack of drive is due to the weather, heat and humidity have sapped what drive I was able to muster on multiple occaisions.

So if I haven't been getting out into the shop, what have I been working on?

RaspberryPi!

I ordered a Raspberry Pi Zero W a while back with plans to use it in an amateur radio project. That project is kind of on hold, so I am rebuilding one of my original RPi projects, a digital picture frame.

I had a couple of RPi model 3's sitting around, so I decided to make them do something.

I've been running Plex Media Server on my FreeBSD file server for a couple of years now, and while it started out pretty good, I feel like the project has started to bloat. I did some searching on the the internets, and found a project called Jellyfin that seems to be closer to what I want, so that is now runnign on a RPi3. When I first set it up, I plugged a 4TB HDD in a USB 3.1 enclosure into it as a place to put all of the content. That worked, but felt a little pokey. After a couple of changes to the /usr/local/etc/smb4.conf, I had a CIFS share that I could access from the RPi. Now it's much quicker, still serves up content to the Roku player, and so the installation is going to be retired.

Another piece of software that I have been messing with off and on over the years is NextCloud. I've appreciated and liked a lot of the things that various companies have come up with over the years to try and make our lives easier/better. However, as time has passed, and the once famous motto of "Don't be evil" was eroded and eventually removed, in general I have found a lot of the "free" offerings to be... not worth it. The goal of NextCloud is to allow you to manage, and thus control, your own data. Much like the Jellyfin initial setup, I used a 4TB drive over USB as a data store, but moved that to the FreeBSD file server as well.

The FreeBSD file server itself, I should probably call it a NAS, but that seems kind of pretentious, has 4 x 4TB drives in a ZFS zraid1 configuration, this is more traditionally known as RAID5, one disk can fail and no data is lost. Over the years I have swapped out several of the disks as they have failed. While I technically could probably get my backup solution, SpiderOak One running on it through some linux emulation shenanigans, it's not supported by SpiderOak, so instead I am just backing it up from my workstation over the network.

While messing with the RPi0W, the 2 x RPi3... I snagged a couple of the newer RPi4 models. I have an RPi4 8GB and an RPi4 4GB now. I don't have anything actually planned for the 8GB one, but the 4GB one is running Pi-hole, which is a local DNS server/filter. It blocks A LOT of advertising and tracking DNS traffic. I'm contemplating using the DHCP server that comes with the Pi-hole instead of the one built into my router, partially because I am getting annoyed with any little change that I make to the configuration resulting in a couple of seconds of no internet access.

So now I have 6 "production" RPi devices on the network, because an older RPi2 is running software to monitor the devices on my network, and also the devices off of my home network that run things like this website and my email. That means I have to manage them. And while that isn't a HUGE amount of stuff to keep track of, it's more than enough to justify dusting off another skillset I haven't used much in the last couple of years, configuration management. So I'm learning all of the stuff that has changed with Ansible in the last couple of years, so that I can run one command and any changes that need to be made or updates that need to be installed, are done. It will also mean that turning up another picture frame, or adding another RPi to the fleet should be relatively painless.

So while I haven't been out in the garage, and haven't had any pictures to share of stuff I have built, I've still been busy. Hopefully soon I'll get back to making some shavings and saw dust.

Garage storage actually working

Today was a good day spent in the garage. I spent some time batching out some components and making a jig for putting the holes in for the retention pins.

/images/french_cleat_garage/IMG_20210320_130521244_HDR.jpg

The nice thing about working with aluminium is that woodworking power tools will cut and grind it just fine. So my miter saw can make the cuts, and my small belt sander can clean up the edges.

/images/french_cleat_garage/IMG_20210320_130527177_HDR.jpg

I just had to use some blocks of wood to hold the 3/8" rod in place.

/images/french_cleat_garage/IMG_20210320_143939973_HDR.jpg

One of the more tedius things was marking out the location to drill the holes for the pins to drop in to secure the tool holder so it doesn't get bumped off the wall. So I made a jig using some scraps of plywood, some t-nuts, washers, and some short bolts.

/images/french_cleat_garage/IMG_20210320_144253231.jpg

This way I can stick a tool holder base into the jig, run the drill press down, flip the board over and run the drill press again, and I have both holes.

/images/french_cleat_garage/IMG_20210320_200457995.jpg

I made three of the wall mounting cleat boards, but have only put up two so far, each one is 4' long. The snow shovels on the left are actually double stacked because we can, that's how they hang at the store.

/images/french_cleat_garage/IMG_20210320_200508272.jpg

So far this appears to be working pretty well, now I just need to finish making the hangers and getting the rest of the tools up there. I also mounted this lower than the previous system. Our longest hanging tool is the push broom.

More garage storage and a push stick

Added a requested modification to the first hanger. There was a concern that with the wind blowing, they could still get knocked off the hanger, so I added a lip to the end.

/images/french_cleat_garage/IMG_20210314_170911458.jpg

The next piece that got some work done was one of the broom hangers, or anything that has a ring at the end of the stick.

/images/french_cleat_garage/IMG_20210314_170919070.jpg

I was originally going to use the aluminium rod as well for that, but decided to use some poplar with a bit of wood glue and a brad shot into the end to help hold in place.

/images/french_cleat_garage/IMG_20210314_170938673.jpg

Today I also decided to make a better push stick instead of using whatever random piece of wood happens to be in reach.

I used a leftover piece of deck board, ripped a 1.5" piece off of one edge, added a roundover to the cut off to make it more comfortable to grip. Cut a 22.5 degree angle off of one end of the leftover board, screwed the handle to it. Then I cut a small piece and screwed it below the handle to act as a catch. If the catch gets chewed up, I can unscrew it and put a new on on. The goal is to keep my hand well away from the blade, even if I do something dumb like have the blade all the way up while cutting something thin.

/images/french_cleat_garage/IMG_20210314_170959440.jpg

Prototype garage storage

Now that the weather has started to warm up, I'm getting back into the shop, err, I mean the garage, to make some sawdust.

Along with trying to get rid of things that I'm not using or we don't need, this year I want to redo the storage that we have for our shovels, rakes, and other yard tools. Several years ago we bought a "system" that used plastic panels screwed to the wall that uses metal S hooks to hold tools. This... mostly works. But there are many times when even just a strong wind will cause things to shift and at least in a couple of cases, fall down.

To correct this, I'm planning to put up french cleat hangers for each tool. This way each tool will be held securely, and if we get rid of something, we can remove that hanger, and if we get something new, I can make a new one.

I'm using 1/2" plywood for this project. This afternoon I created my prototype.

/images/french_cleat_garage/IMG_20210313_191342948.jpg

This short wall portion will be much longer to accomodate multiple tools. To the left you can see the plastic and S hook solution.

/images/french_cleat_garage/IMG_20210313_191425305.jpg

The "hanger" is just a piece of 2x4 that has a 10 degree slice off one side, this will probably be 15 degrees in the final version.

/images/french_cleat_garage/IMG_20210313_191452588.jpg

The handle of a shovel will slide right over that chunk of 2x4 and should be pretty stable. By being 1.5 inches off the wall, the shovel can hang "back" closer to the wall, since these things do not hang straight up and down.

You may be wondering about the holes in the panel...

/images/french_cleat_garage/IMG_20210313_191517021.jpg

These are 3/8" holes to hold some aluminium rod pieces that are a little over 1.25 inches long. These go in about 1/16" below the board at the top, and prevent the cleat from coming off of the wall. This way when taking the shovel off or hanging it up, it doesn't get knocked off the wall. The pins are snug, but can be removed to allow the cleat to move up and be taken off.

/images/french_cleat_garage/IMG_20210313_191616597.jpg

Now I just need to make a hanger for the tools that DON'T have wide handles, and I can make my new tool hangers.

I can't claim that this is totally an original idea of mine, I was inspired by several other people, including

https://www.youtube.com/watch?v=x6I5Bx4M5wc

Checking passwordsafe entries against https://haveibeenpwned.com/

I wanted to check my current passwordsafe database passwords against the data at haveibeenpwned, however I don't like the idea of using the API or the webform to send all of my passwords to a 3rd party.

So I wrote a python script.

#!/usr/bin/env python


import hashlib
import pypwsafev3
from getpass import getpass
import argparse


def getArgs():
    p = argparse.ArgumentParser(description='PasswordSafe hashes')
    p.add_argument('-f', help='PasswordSafe database file')
    return p.parse_args()


def main():
    args = getArgs()

    pw = pypwsafev3.PWSafe3(args.f, getpass('PasswordSafe master:' ))

    with open('hashes.txt', 'w') as f:
        for i in pw.listall():
            f.write('{}, {}\n'.format(i[1], hashlib.sha1(str.encode(i[4])).hexdigest()))


if __name__ == '__main__':
    main()

This generates a text file named "hashes.txt" which contains the name of the password entry and the sha1 hash of the password. Then I could search the pwned-passwords-sha1-ordered-by-count-v5.txt file for them to see if any of them are in the list.

$ sed 's/ //g' hashes.txt | awk -F, '{print $2}' | grep -i -F -f - pwned-passwords-sha1-ordered-by-count-v5.txt

Borked Phone

For the last couple of days my phone has been kind of a pain to work with. I would use the keyboard to type something in, and either the entirely wrong letters would show up, or nothing at all. Last night I got around to grabbing an app off the Play Store to show where touch events were detected and then turned on the developer options that do pretty much the same thing.

I rebooted my phone, I rebooted my phone into safe mode, nothing helped.

This is a screenshot using the app I downloaded. I basically ran my finger all over the screen, and I noticed this area where nothing showed up.

/images/Screenshot_20180502-225826.thumbnail.png

So then I tried it with the developer options turned on.

/images/Screenshot_20180502-231703.thumbnail.png

That dead area makes my phone pretty much unusable. Thankfully my phone is still under warranty, and I'll be able to send it in and get a replacement. In the mean time I am charging up my Nexus 6 and will transfer my number back to it so that I have a working phone until the replacement arrives.

Am I me?

This is going to ramble a bit...

I was watching a youtube video, "Star Talk" with Neil deGrasse Tyson, Adam Savage, Matthew Liao, and Chuck Nice.

In the second segment, there was a discussion on uploading consciousness.

Every morning I wake up, and I'm me. I'm not somebody else. ... Maybe I'm not me, and I don't know it. Because in the act of becoming someone else, I am that other person. -- Neil deGrasse Tyson

I think that what we think of as "growing" as an individual, could also be expressed as evolving, of becoming another person.

My identity, the person that I was in the past, is not the same person that I am today. It is possible to look at the former me, and the present me, and see the progression, the journey. But I would not want to be that person again.

The previous versions of me were not as empathetic or sympathetic. The previous versions of me were judgmental, viewing the world through a narrow lens that was only my own perspective.

The current me, and I hope the future me, will continue to try to see the world through the eyes and experiences of others. Just because it hasn't happened to me, just because I have not experienced it, does not mean that it has not, or will not, happen to someone else.

Raspberry Pi running FreeBSD as a NAT and Samba server

The Four Lakes Amateur Radio Club has been using a Raspberry Pi 1B+ for a couple of years as our DHCP/Samba/NAT server for events like ARRL Field Day.

As I had a spare RPi 2 sitting around, I decided to see if I could use FreeBSD on that device instead, instead of Debian based Raspbian.

I am using the FreeBSD 11.1-RELEASE image for the the OS, the instructions on the FreeBSD website were easy to use to get the image transferred to an SD card. Once we were booted up and running, using the ethernet port for network connectivity, I installed the wpa_supplicant package, I probably could have skipped this step and used the wpa_supplicant installation in the base system.

I had to update /boot/loader.conf

legal.realtek.license_ack=1
if_urtwn_load="YES"
wlan_wep_load="YES"wlan_ccmp_load="YES"
wlan_tkip_load="YES"

Additions to /etc/rc.conf

ntpd_enable="YES"
ntp_sync_on_start="YES"
wlans_urtwn0="wlan0"
ifconfig_wlan0="WPA SYNCDHCP"

The ntp additions are due to the RPi not having a Real Time Clock, these settings force the RPi to update the time from network clocks at boot time.

Create the /usr/local/etc/wpa_supplicant.conf file

ctrl_interface=/var/run/wpa_supplicant
eapol_version=1
ap_scan=1
fast_reauth=1
country=US
device_name=fpi
network={
    ssid="SECRET"
    proto=WPA
    key_mgmt=WPA-PSK
    pairwise=CCMP TKIP
    group=CCMP TKIP WEP104 WEP40
    psk=SUPER_SECRET
}

And then reboot to have all of the changes take effect.

Once we were up and running on WiFi, I reconfigured the ethernet port for a static IP by changing the configuration in /etc/rc.conf from

ifconfig_ue0="DHCP"

to

ifconfig_ue0="inet 10.0.0.1 netmask 255.255.255.0"

Then I installed dnsmasq and samba.

pkg install dnsmasq
pkg install samba48

/usr/local/etc/dnsmasq.conf

domain-needed
bogus-priv
no-resolv
server=1.1.1.1
interface=ue0
expand-hosts
domain=local
dhcp-range=10.0.0.10,10.0.0.50,6h
dhcp-option=3,10.0.0.1
dhcp-leasefile=/usr/local/var/lib/misc/dnsmasq.leases

/usr/local/etc/smb4.conf

[global]
    workgroup = WORKGROUP
    server string = Samba Server Version %v
    netbios name = fpi
    wins support = yes
    security = user
    passdb backend = tdbsam
    map to guest = Bad User
    log file = /var/log/samba4/log.%m
    log level = 3

[fd]
    comment = Field Day
    create mask = 0664
    directory mask = 0775
    force group = nobody
    force user = nobody
    guest ok = yes
    path = /home/fd
    read only = no

And added to /etc/rc.conf again

dnsmasq_enable="YES"
samba_server_enable="YES"
winbindd_enable="YES"

The directory where we will be sharing files from is /home/fd, so we need to create it and set permissions.

mkdir /home/fd
chown nobody:nobody /home/fd
chmod 775 /home/fd

Now for the NAT portion, since I used to run an OpenBSD firewall for my home network, I decided to use pf instead of ipfw.

So we need to make some more changes to /etc/rc.conf

pf_enable="YES"
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
gateway_enable="YES"

And create /etc/pf.conf

ext_if='wlan0'
int_if='ue0'
localnet = $int_if:network
nat on $ext_if from $localnet to any -> ($ext_if)

Yes, there should probably be more rules here to restrict access and ports.

Now it's time for another reboot and everything should be working.

Blocking IPs for failed ssh logins to jails on FreeBSD

I recently got sslh working on my home FreeBSD server. What made this more complicated is that I wanted ssh to go to one jail and https to go to a different jail.

My jail host is 172.27.1.2, the target for ssh is 172.27.1.4, the target for https is 172.27.1.5. The https jail runs a reverse nginx proxy to forward to various other jails and devices on my home network.

Something that I used to use on linux hosts was fail2ban to block the constant brute force ssh attempts against my system. This time around I decided to try something a little simpler. I found this wiki article describing how to use ipfw and a cron job to update a blocklist.

I had to configure ssh on 172.27.1.4 listen on both 22 and 8022, if I tried to just use 22 I could not reach that jail from my local network.

Below are the pieces that make this all work.

My /usr/local/etc/sslh.conf

# This is a basic configuration file that should provide
# sensible values for "standard" setup.

verbose: false;
foreground: false;
inetd: false;
numeric: false;
transparent: true;
timeout: 2;
user: "root";
pidfile: "/var/run/sslh.pid";


# Change hostname with your external address name.
listen:
(
        { host: "172.27.1.2"; port: "443"; }
);

protocols:
(
        { name: "ssh"; service: "ssh"; host: "172.27.1.4"; port: "8022"; fork: true;},
        { name: "ssl"; host: "172.27.1.5"; port: "443"; log_level: 0; }
);

My /etc/ipfw/sslh.rules

#!/bin/sh

ipfw add 20000 fwd 172.27.1.2,443 log tcp from 172.27.1.5 443 to any out
ipfw add 30000 fwd 172.27.1.2,443 log tcp from 172.27.1.4 8022 to any out

My /root/sshd-fwscan.sh

#!/bin/sh

# based on http://www.freebsdwiki.net/index.php/Block_repeated_illegal_or_failed_SSH_logins
# Copyright (c) 2004,2005 RPTN.Net,
# Copyright (c) 2005 DaveG.ca,
# Copyright (c) 2006 Bob (kba at ats32.ru)
# You may use this code under the GPL, version 2 or newer.
# Updates for IPF by Sasha.by
# Copyright (c) 2018 Matt Okeson-Harlow, https://technomage.net
# 2018-04-29

# changed rule number to 10000 to not impact sslh rules at 20000
# exclude 172.27.1 as that is the home network
# exclude remote hosts that I control
# lowered the count to 3 from 5
# use find to locate auth.log.*.bz2 files modified in the last 2 days

PATH=/bin:/usr/bin:/sbin:/usr/sbin
LOGDIR=/usr/jails/kotilo/var/log
RULE=10000

# exclude local network, yoda and leia
EXCLUDE='172[.]27[.]1|71[.]19[.]155[.]130|71[.]19[.]157[.]86'

# log the current rules before we clear them
ipfw show ${RULE} | logger -p local0.notice -t sshd-fwscan

# clear the current rules
if ipfw show | awk '{print $1}' | grep -q ${RULE} ; then
    ipfw delete ${RULE}
fi

# This catches repeated attempts for both legal and illegal users
# No check for duplicate entries is performed, since the rule
# has been deleted.

(find ${LOGDIR} -mmin -$((60*24*2)) -name "auth.log.*.bz2" -exec bzcat {} \;; cat ${LOGDIR}/auth.log) |
awk '/sshd/ && (/Invalid user/ || /authentication error/) {try[$(NF)]++}
END {for (h in try) if (try[h] > 3) print h}' | egrep -v ${EXCLUDE} |
while read ip
do
        ipfw -q add ${RULE} deny tcp from $ip to any in
done

I added the following to my /etc/crontab

#
# sshd-fwscan to block failed logins
*/10    *   *   *   *   root    /root/sshd-fwscan.sh