Cheating at Wordle with grep

I usually try to make a good effort at Wordle, but sometimes I get down to the last one or two chances and need some help. Instead of anything fancy-pants, I usually turn to a dictionary file and my friend, grep.

So, first thing's first, you need a dictionary file, which is just a file with a bunch of words one-per-line. These are usually found in /usr/share/dict. I happen to have cracklib-small on my machine so we'll use that.

First, you'll want to get all the five-letter words out of the file. I use the regex ^\w{5}$, which is ^ for the start of the line, \w for an alphanumeric character, {5} saying that there are 5 of them, and $ for the end of the line. The beginning and end of line markers are important, otherwise you'll get words that contain 5 or more letters.

grep -E '^\w{5}$' /usr/share/dict/cracklib-small

At this point, I've already made some guesses and have a few letters in the right spot, and some letters which are correct but in the wrong spot. We'll bucket these into two greps.

For letters in the right spot, I stick those right into a regex. For example, let's say I know the word starts with 'f' and 'a':

grep -E 'fa\w\w\w'

For the right letters in the wrong spot, I simply use the letter as the regex. If I have multiple letters, I can chain those together by piping grep like so:

grep s | grep t

So chaining them all together:

$ grep -E '^\w{5}$' /usr/share/dict/cracklib-small \
    | grep -e 'fa\w\w\w' \
    | grep s | grep t
facts
fasts
fates
faust

You could eliminate words that have letters you've already eliminiated by chaining grep -v <letter> to the end, but I find that pretty cumbersome. There's only a handful of possible words at this point, so I think it's easier to just remove them in my head.

read more

KVM USB Auto-Passthrough

I do all of my PC gaming on a Windows VM which I run on a Linux host running KVM. With a new gaming monitor on the way, I got the idea of using a DisplayPort/USB switcher to switch my keyboard, mouse, and monitor between my laptop and Windows VM (via KVM's USB passthrough). That way I can connect the monitor directly to the Windows VM and use its 144 Hz refresh rate instead of being stuck at what Linux is displaying along with the 30 or 60 fps provided by Parsec.

Before I buy that USB switcher, I need to make sure that I can have my USB devices to auto-connect to the VM when they get connected to my Linux host.

Through my cursory searching I couldn't find a way native to libvirt/qemu to do this, so udev to the rescue! Through udev rules, I'm able to detect when a device matching some parameters is connected, and then run a command. This command will get a bunch of environment variables set from udev. The interesting ones to us are:

  • ACTION - add, remove, etc.
  • ID_VENDOR_ID - the USB vendor ID
  • ID_MODEL_ID - the USB model ID.

To test this idea out, I set up a simple rule that matches against my keyboard and saved this as /etc/udev/rules.d/90-libvirt-usb.rules:

ACTION=="bind", \
  SUBSYSTEM=="usb", \
  ENV{ID_VENDOR_ID}=="6b62", \
  ENV{ID_MODEL_ID}=="6869", \
  RUN+="/usr/local/bin/kvm-udev attach steam"
ACTION=="remove", \
  SUBSYSTEM=="usb", \
  ENV{ID_VENDOR_ID}=="6b62", \
  ENV{ID_MODEL_ID}=="6869", \
  RUN+="/usr/local/bin/kvm-udev detach steam"

The VENDOR_ID and MODEL_ID can be found by running the lsusb command, which shows this as "ID vendor_id:model_id", for example "ID 6b62:6869".

And of course, here's the script /usr/local/bin/kvm-udev which takes care of the auto-connecting. It takes two parameters, first either being "attach" or "detach" and the second being the name of the KVM domain (aka VM).

#!/bin/bash

# Usage: ./kvm-udev.sh attach|detach <domain>

set -e

ACTION=$1
DOMAIN=$2

CONF_FILE=$(mktemp --suffix=.kvm-udev)
cat << EOF >$CONF_FILE
<hostdev mode='subsystem' type='usb'>
  <source>
    <vendor id='0x${ID_VENDOR_ID}' />
    <product id='0x${ID_MODEL_ID}' />
  </source>
</hostdev>
EOF

virsh "${ACTION}-device" "$DOMAIN" "$conf_file"
rm "$CONF_FILE"

This writes out a temporary file which contains some libvirt XML config for doing device passthrough, picking details from the environment variables that udev sets. It then calls virsh to attach/detach the device to the given domain using that temporary config file.

And with that, every time I plug my keyboard into my KVM host, it automatically routes it to my Windows VM! Now that this works, I can add an additional rule for my mouse, so that switching these devices between computers works smoothly.

read more

"Key was rejected by service" kernel module error on cloned VMs

Here's a quick blurb about something I recently ran into and found a fix for, and I'm hoping that the search indexing gods find this and help some other poor soul who has run into this sort of thing.

I've been playing around with KVM virtual machines on my home server recently, and have started using the virt-sparsify and virt-resize CLI tools respectively to generate a compressed golden machine image and apply that image to a new VM. For example:

sudo virt-sparsify --compress --convert qcow2 /dev/vg0/debian-base debian-base.qcow2
sudo virt-resize --expand /dev/sda2 --no-sparse debian-base.qcow2 /dev/vg0/new-vm

After doing this and booting the new machine, I got this failure after trying to load in a kernel module:

$ sudo modprobe bridge
modprobe: ERROR: could not insert 'bridge': Key was rejected by service

Uhhh, what? This seems to point to some secure boot signing-related thing, but I'm pretty sure nothing has gone awry with that since all I did was make a disk clone. After a bunch of experimenting, I discovered that cloning with straight dd would work fine, and would somehow taint the target disk so that future virt-resize runs would always result in a working target!

This was really weird, so I dug through the virt-resize manpage, and came across the --no-sparse flag which has this in its description:

The main time this can be a problem is if the target is a host partition (eg. virt-resize source.img /dev/sda4) because the usual partitioning tools tend to leave whatever data happened to be on the disk before.

If you have to reuse a target which contains data already, you should use the --no-sparse option. Note this can be much slower.

Well shit. My target VM that's receiving the image is using a LVM logical volume for its drive, which I'm sure has some leftover data on it. virt-resize --no-sparse fixes this issue for me, as does zeroing out the LV before applying the image. With the sparse copying, some old junk data must have been lurking in the new VM's partition, causing the issues.

read more

Home VPN with Wireguard

If you have an interest in Linux networking, by now you've probably heard of Wireguard. In case you haven't, it's a newer cross-platform VPN whose main attraction is that it's way way easier to set up on Linux than other VPNs that have come before it. If you've ever had to set up an IPSec VPN using Racoon or Openswan or StrongSwan or any other weird animal-based tool, then you know how much of a royal pain in the ass it is.

While I was on a tear improving my home network, I decided to finally bite the bullet and set Wireguard up on my router and laptop, allowing me to securely connect to my home network from anywhere. This post outlines what I did to make that happen, in case you want to replicate it in your own home network.

Fair bit of warning though: I'm assuming that you already have basic knowledge of networking: subnetting, routing, that kind of stuff.

read more