Skip to main content

Posts

Writing Sudoku Solvers

After writing a Nonogram solver, I decided to tackle a Sudoku solver to practice Rust. My goal wasn't just to support classic Sudoku rules, but also to handle variants like Thermometer, Arrow, and Cage etc. 1. Brute Force It is fairly easy to write a brute force or backtracking algorithm. This approach is sufficient for most classic Sudoku puzzles, but it becomes unbearably slow as soon as variant rules are introduced. I considered this step a warmup—a baseline to improve upon. 2. Constraint Propagation Here, I tried to introduce "logical thinking" to the algorithm. I used  u16  as a bitmask to represent the possible values of a cell. Whenever a cell's state changes (due to guessing, backtracking, or propagation), the algorithm consults all constraints to eliminate impossible candidates. While Nonogram is technically an NP-Complete problem, in practice, my constraint-propagation solver (without guessing) can solve almost all puzzles found online. I’ve only seen one ex...
Recent posts

An Adventure with Qubes OS

I've been experimenting with Qubes OS on my new laptop and wanted to share some notes on the experience. Hardware Overall, Qubes OS works quite well on my hardware. Aside from typical issues like deep sleep, speaker performance, and touchpad scroll speed, the experience has been smooth. I particularly like that I can boot directly from a microSD card. This allowed me to move the  /boot  partition to the card while completely disabling USB access in  dom0  for better security. Detached  /boot  and LUKS Header Moving  /boot  and the LUKS header to a microSD card is a fun project, but it has some drawbacks: I have to remember to mount  /boot  before updating  dom0 . The system won't shut down properly if I forget to unmount  /boot . Testing Qubes OS 4.3 rc3 I decided to test the Qubes OS 4.3 rc3 release by performing an in-place upgrade. Unfortunately, the system failed to boot afterward. dracut  Issues After the upgrade, the...

A Rocky Migration: Moving from docker-compose to Podman and gVisor

I've been running a few containers for several years. They were all running under rootless Docker with a single user. Initially, I planned to  migrate the containers to VMs , but I couldn't get a stable workflow after about two months of effort. Later,  gVisor caught my attention , and I decided to migrate to Podman with gVisor instead. The new plan is to run each container with  --userns=auto  and use Quadlet for systemd integration. This approach provides better isolation and makes writing firewall rules easier. I'm now close to migrating all my containers. Here are a couple of rough edges I'd like to share. Network Layout I compared  various networking options  and spent a few hours trying the one-interface-per-group approach before giving up. I settled on a single macvlan network and decided to use static IP addresses for my containers. To prevent a randomly assigned IP address from conflicting with a predefined one, I allocated a large IP range for my ...

Hardening Container Network Security: Filtering Outgoing Traffic

I want to filter the outgoing network traffic for all of my containers based on a set of rules. For example: Some containers should be blocked from accessing the internet entirely. Some containers should have unrestricted internet access. Some containers should be able to access the internet, but not a specific list of URLs. Some containers should only be allowed to access a specific list of URLs. To manage this, I will define logical policy groups and assign each container to one. As a general rule, only DNS and HTTP/HTTPS traffic will be permitted. Option 1: A Proxy for Each Policy Group Imagine Container A is only allowed to access  www.google.com . Here’s how this approach would work: Create an Nginx (or  socat ) container that listens on port 443 and acts as a reverse proxy for  www.google.com . Place both the Nginx proxy and Container A into an  internal  container network. Within this network, add  www.google.com  as a network alias for the Ngin...

A Journey into Podman: Notes on My First Adventure

For the last few days, I've been experimenting with Podman. My goal was to get a feel for the setup, create a minimal yet scalable environment for a few containers, and identify potential problems early on. Here are my notes from this experience. [Updates 2025-09-21] Added more networking options and other information. Quadlet Quadlet  allows you to define containers, networks and more using a syntax similar to systemd. This includes helpful features like drop-in overrides and templates. The framework is tightly integrated with systemd, and Quadlet actually generates real systemd units. This means I can directly write systemd options in my Quadlet files. One of the biggest benefits I've found is how easy Quadlet makes it to set up socket activation. This allows me to place some containers in an internal network or even without a network at all. Hardening Defaults Let's say I have a group of Systemd and Quadlet units, all named in the format of  xyz-* . My goal is to define ...

gVisor: A Fresh Look at Container Security

My original plan was to stabilize my  VM pipeline  before deploying containers using a hardened stack of Podman, QEMU, SELinux, and user namespaces ( --userns=auto ). However, the pipeline's complexity grew, requiring script rewrites and schema redesigns, and the process took much longer than anticipated. In the meantime, an interesting alternative has captured my attention:  gVisor . It occupies a unique space between traditional SELinux policies and full-blown virtual machines, offering a compelling set of trade-offs. What is gVisor? At its core, gVisor is an application kernel, written in the memory-safe language Go, that provides an additional layer of isolation between containerized applications and the host operating system. It's essentially a user-space implementation of the Linux kernel's system call interface. The security model is explained  here . gVisor in Practice gVisor provides an OCI-compliant runtime called  runsc , which can be almost transpare...

A Declarative Approach to Config File Management

Configuration files for different services are rarely independent. For example, in nftables, I might tag traffic with a firewall mark, and that mark is then used by systemd-networkd or in ip routes. Similarly, when the name of the primary network interface changes, multiple services like nftables, postfix, and samba need to be updated. Requirements I want to define core data in one place, then update all config files with a simple command. If a configuration file is modified by an external process (for example, a package update from a vendor or distribution), the changes must be handled gracefully. Either the merge should be automatic and permanent, or I should be notified to easily resolve any conflicts. It should be obvious within the config file itself what changes I have made. Existing Solutions I did some quick survey and found a few options. 1. Templates These tools render a template using provided data sources. To manage  /etc/config.txt , I would create a  /etc/config....