Alix 2D3 OpenBSD Firewall Gateway

Posted on February 08, 2025 in Tech-Recipe

[!NOTE] The environment used for this was: Mac Air M2 8gb MacOS Sequoia 15.3

Notes on Setup of an Alix 2D3 with OpenBSD to act as a Firewall/Gateway

Download and verify:

Get a copy of OpenBSD, in this case the amd64 install image. From here: https://cdn.openbsd.org/pub/OpenBSD/7.6/amd64/

And make sure to check the sha256sum against the published value1:

sha256sum ./Downloads/install76.img
973dfa837e4998f6c0f29d0afc9f40d85e29a3d2b25fcea8b3f13b4491fbedc0  ./Downloads/install76.img

Create install media

Insert a USB stick into the Macbook:

diskutil list
/dev/disk4 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *62.5 GB    disk4
   1:                       0xEF                         491.5 KB   disk4s1
   2:                    OpenBSD                         729.3 MB   disk4s4
                    (free space)                         61.8 GB    -

Our external disk is /dev/disk4 - so now we can copy the install image, unmount the disk first:

diskutil unmountDisk /dev/disk4
sudo dd if=./Downloads/install76.img of=/dev/disk4 bs=1m

Boot the Alix 2D3

First you need a serial cable, insert it into the serial port of the Alix (powered off) and also into the USB port of the Macbook. You need to identify the serial device:

ls /dev/cu.*
/dev/cu.usbserial-11210

So now we can make a screen connection to the serial port. Note that the default baud rate is 38400, but it can be set in the BIOS to 115200:

screen /dev/cu.usbserial-11210 115200

NOTE: to leave a screen session press CTRL+a, k then y

Insert the USB device into the Alix 2D3 and put the power onto the Alix 2D3. You will see a screen like this:

SeaBIOS (version ?-20160307_153453-michael-desktop64)
XHCI init on dev 00:10.0: regs @ 0xfeb22000, 4 ports, 32 slots, 32 byte contexts
XHCI    extcap 0x1 @ feb22500
XHCI    protocol USB  3.00, 2 ports (offset 1), def 0
XHCI    protocol USB  2.00, 2 ports (offset 3), def 10
XHCI    extcap 0xa @ feb22540
Found 2 serial ports
ATA controller 1 at 4010/4020/0 (irq 0 dev 88)
EHCI init on dev 00:13.0 (regs=0xfeb25420)
ATA controller 2 at 4018/4024/0 (irq 0 dev 88)
Searching bootorder for: /pci@i0cf8/*@14,7
Searching bootorder for: /rom@img/memtest
Searching bootorder for: /rom@img/setup
ata0-0: KINGSTON SMS200S330G ATA-8 Hard-Disk (28626 MiBytes)
Searching bootorder for: /pci@i0cf8/*@11/drive@0/disk@0
XHCI port #3: 0x00200e03, powered, enabled, pls 0, speed 3 [High]
Searching bootorder for: /pci@i0cf8/usb@10/storage@3/*@0/*@0,0
Searching bootorder for: /pci@i0cf8/usb@10/usb-*@3
USB MSC vendor='SSK' product='USB3.2' rev='' type=0 removable=1
USB MSC blksize=512 sectors=122136576
Initialized USB HUB (0 ports used)
All threads complete.
Scan for option roms
PCengines Press F10 key now for boot menu:

Note that to press F10 on the Macbook Air you need to press fn+F10...

Select boot device:

1. USB MSC Drive SSK USB3.2
2. ata0-0: KINGSTON SMS200S330G ATA-8 Hard-Disk (28626 MiBytes
3. Payload [memtest]
4. Payload [setup]

Install OpenBSD

First of all, we need to stop the Alix going into a boot loop over the serial console. Select the USB drive from the boot menu, then do this:

Booting from Hard Disk...
Booting from 0000:7c00
Using drive 0, partition 3.
Loading......
probing: pc0 com0 com1 mem[638K 1918M a20=on]
disk: hd0+ hd1+
>> OpenBSD/amd64 BOOT 3.67
boot> stty com0 115200
boot> set tty com0
switching console to com0
>> OpenBSD/amd64 BOOT 3.67
boot> bsd.rd

The important lines are:

boot> stty com0 115200
boot> set tty com0
boot> bsd.rd

You should get to this point, at which stage you can follow any OpenBSD install guide, but it is very simple:

Welcome to the OpenBSD/amd64 7.6 installation program.
WARNING: / was not properly unmounted
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?

Press I to install and follow onscreen instructions, note that NIC em0 is the one closest to the serial port.

WARNING: / was not properly unmounted
(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? I
At any prompt except password prompts you can escape to a shell by
typing '!'. Default answers are shown in []'s and are selected by
pressing RETURN.  You can exit this program at any time by pressing
Control-C, but this can leave your system in an inconsistent state.

Terminal type? [vt220]
System hostname? (short form, e.g. 'foo') cappuccino

Available network interfaces are: em0 em1 em2 vlan0.
Network interface to configure? (name, lladdr, '?', or 'done') [em0]
IPv4 address for em0? (or 'autoconf' or 'none') [autoconf]
IPv6 address for em0? (or 'autoconf' or 'none') [none]
Available network interfaces are: em0 em1 em2 vlan0.
Network interface to configure? (name, lladdr, '?', or 'done') [done]
Using DNS domainname my.domain
Using DNS nameservers at 213.140.210.232 213.140.211.232

Password for root account? (will not echo)
Password for root account? (again)
Start sshd(8) by default? [yes]
Change the default console to com0? [yes]
Available speeds are: 9600 19200 38400 57600 115200.
Which speed should com0 use? (or 'done') [115200]
Setup a user? (enter a lower-case loginname, or 'no') [no] jas
Full name for user jas? [jas]
Password for user jas? (will not echo)
Password for user jas? (again)
WARNING: root is targeted by password guessing attacks, pubkeys are safer.
Allow root ssh login? (yes, no, prohibit-password) [no]
What timezone are you in? ('?' for list) [Asia/Nicosia]

Available disks are: sd0 sd1.
Which disk is the root disk? ('?' for details) [sd0]
Encrypt the root disk with a (p)assphrase or (k)eydisk? [no]
Disk: sd0       geometry: 3649/255/63 [58626288 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0 ] Unused
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] Unused
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] Unused
*3: A6      0   1   2 -   3648 254  63 [          64:    58621121 ] OpenBSD
Use (W)hole disk MBR, whole disk (G)PT, (O)penBSD area or (E)dit? [OpenBSD]
The auto-allocated layout for sd0 is:
#                size           offset  fstype [fsize bsize   cpg]
  a:          1004.7M               64  4.2BSD   2048 16384     1 # /
  b:          1789.4M          2057632    swap
  c:         28626.1M                0  unused
  d:          1487.5M          5722240  4.2BSD   2048 16384     1 # /tmp
  e:          2302.2M          8768576  4.2BSD   2048 16384     1 # /var
  f:          3209.3M         13483392  4.2BSD   2048 16384     1 # /usr
  g:           896.8M         20056128  4.2BSD   2048 16384     1 # /usr/X11R6
  h:          3588.0M         21892768  4.2BSD   2048 16384     1 # /usr/local
  i:          2389.9M         29241056  4.2BSD   2048 16384     1 # /usr/src
  j:          5803.7M         34135488  4.2BSD   2048 16384     1 # /usr/obj
  k:          6152.2M         46021536  4.2BSD   2048 16384     1 # /home
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a]
/dev/rsd0a: 1004.7MB in 2057568 sectors of 512 bytes
5 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0k: 6152.2MB in 12599648 sectors of 512 bytes
31 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0d: 1487.5MB in 3046336 sectors of 512 bytes
8 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0f: 3209.3MB in 6572736 sectors of 512 bytes
16 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0g: 896.8MB in 1836640 sectors of 512 bytes
5 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0h: 3588.0MB in 7348288 sectors of 512 bytes
18 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0j: 5803.7MB in 11886048 sectors of 512 bytes
29 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0i: 2389.9MB in 4894432 sectors of 512 bytes
12 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
/dev/rsd0e: 2302.2MB in 4714816 sectors of 512 bytes
12 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each
Available disks are: sd1.
Which disk do you wish to initialize? (or 'done') [done]
/dev/sd0a (52d29e0dc555db56.a) on /mnt type ffs (rw, asynchronous, local)
/dev/sd0k (52d29e0dc555db56.k) on /mnt/home type ffs (rw, asynchronous, local, nodev, nosuid)
/dev/sd0d (52d29e0dc555db56.d) on /mnt/tmp type ffs (rw, asynchronous, local, nodev, nosuid)
/dev/sd0f (52d29e0dc555db56.f) on /mnt/usr type ffs (rw, asynchronous, local, nodev)
/dev/sd0g (52d29e0dc555db56.g) on /mnt/usr/X11R6 type ffs (rw, asynchronous, local, nodev)
/dev/sd0h (52d29e0dc555db56.h) on /mnt/usr/local type ffs (rw, asynchronous, local, nodev)
/dev/sd0j (52d29e0dc555db56.j) on /mnt/usr/obj type ffs (rw, asynchronous, local, nodev, nosuid)
/dev/sd0i (52d29e0dc555db56.i) on /mnt/usr/src type ffs (rw, asynchronous, local, nodev, nosuid)
/dev/sd0e (52d29e0dc555db56.e) on /mnt/var type ffs (rw, asynchronous, local, nodev, nosuid)

Let's install the sets!
Location of sets? (disk http nfs or 'done') [http] disk
Is the disk partition already mounted? [no]
Available disks are: sd0 sd1.
Which disk contains the install media? (or 'done') [sd1]
  a:          1424384             1024  4.2BSD   2048 16384 16142
  i:              960               64   MSDOS
Available sd1 partitions are: a i.
Which sd1 partition has the install sets? (or 'done') [a]
Pathname to the sets? (or 'done') [7.6/amd64]

Select sets by entering a set name, a file name pattern or 'all'. De-select
sets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'.
    [X] bsd           [X] base76.tgz    [X] game76.tgz    [X] xfont76.tgz
    [X] bsd.mp        [X] comp76.tgz    [X] xbase76.tgz   [X] xserv76.tgz
    [X] bsd.rd        [X] man76.tgz     [X] xshare76.tgz
Set name(s)? (or 'abort' or 'done') [done] -x* -game
    [X] bsd           [X] base76.tgz    [X] game76.tgz    [ ] xfont76.tgz
    [X] bsd.mp        [X] comp76.tgz    [ ] xbase76.tgz   [ ] xserv76.tgz
    [X] bsd.rd        [X] man76.tgz     [ ] xshare76.tgz
Set name(s)? (or 'abort' or 'done') [done]
Directory does not contain SHA256.sig. Continue without verification? [no] yes
Installing bsd          100% |**************************| 28007 KB    00:01
Installing bsd.mp       100% |**************************| 28139 KB    00:01
Installing bsd.rd       100% |**************************|  4600 KB    00:00
Installing base76.tgz   100% |**************************|   414 MB    00:54
Extracting etc.tgz      100% |**************************|   264 KB    00:00
Installing comp76.tgz   100% |**************************| 81512 KB    00:18
Installing man76.tgz    100% |**************************|  8039 KB    00:02
Installing game76.tgz   100% |**************************|  2746 KB    00:00
Installing BUILDINFO    100% |**************************|    54       00:00
Location of sets? (disk http nfs or 'done') [done]
Saving configuration files... done.
Making all device nodes... done.
Multiprocessor machine; using bsd.mp instead of bsd.
fw_update: add amd; update none
Relinking to create unique kernel... done.

CONGRATULATIONS! Your OpenBSD install has been successfully completed!

When you login to your new system the first time, please read your mail
using the 'mail' command.

Exit to (S)hell, (H)alt or (R)eboot? [reboot]

Remove the install media and reboot.

Configuration

First run, do the following to update (run as root, use su):

syspatch
pkg_add -Uu
sysmerge -d
fw_update
reboot

Add nano because who has the time to deal with arrow-keys not being arrow-keys

pkg_add nano

Now, edit the doas users:

nano /etc/doas.conf

And insert the line:

permit nopass :wheel

Now you should log in as the user account (in the wheel group), and then use doas su to perform root operations.

Shutdown un-needed services

We don't need smtpd and sndiod on this machine, shut them down:

cappuccino# rcctl ls on
check_quotas
cron
dhcpleased
library_aslr
ntpd
pf
pflogd
resolvd
slaacd
smtpd
sndiod
sshd
syslogd

cappuccino# rcctl stop smtpd
smtpd(ok)
cappuccino# rcctl disable smtpd
cappuccino# rcctl stop sndiod
sndiod(ok)
cappuccino# rcctl disable sndiod

Network setup

echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf
echo 'inet autoconf' > /etc/hostname.em0 # or use a static IP
echo 'inet 172.20.10.1 255.255.255.0 172.20.10.255' > /etc/hostname.em1
echo 'inet 172.20.20.1 255.255.255.0 172.20.20.255' > /etc/hostname.em2

dhcpd

rcctl enable dhcpd
rcctl set dhcpd flags em1 em2
nano /etc/dhcpd.conf

pf Firewall config

nano /etc/pf.conf

And insert the following:

wired = "em1"
wifi  = "em2"
table <martians> { 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16     \
                   172.16.0.0/12 192.0.0.0/24 192.0.2.0/24 224.0.0.0/3 \
                   192.168.0.0/16 198.18.0.0/15 198.51.100.0/24        \
                   203.0.113.0/24 }
set block-policy drop
set loginterface egress
set skip on lo0
match in all scrub (no-df random-id max-mss 1440)
match out on egress inet from !(egress:network) to any nat-to (egress:0)

match in on { $wired } inet proto { tcp udp } from any to !172.20.10.1 port 53 rdr-to 172.20.10.1
match in on { $wifi } inet proto { tcp udp } from any to !172.20.20.1 port 53 rdr-to 172.20.20.1

antispoof quick for { egress $wired $wifi }
block in quick on egress from <martians> to any

block in quick on { $wired $wifi } proto { tcp udp } from any to any port 853
block in quick on { $wired $wifi } proto { tcp udp } from any to any port 5353

block return out quick on egress from any to <martians>
block all
pass out quick inet
pass in on { $wired $wifi } inet

unbound for DNS

rcctl enable unbound
nano /var/unbound/etc/unbound.conf

And insert the following:

server:
        interface: 172.20.10.1
        interface: 172.20.20.1
        interface: 127.0.0.1
        access-control: 172.20.10.0/24 allow
        access-control: 172.20.20.0/24 allow
        do-not-query-localhost: no
        hide-identity: yes
        hide-version: yes
        prefetch: yes

forward-zone:
        name: "."
        forward-addr: 1.1.1.1  # IP of the preferred upstream resolver

And make sure that the localhost interface takes DNS from the local resolver:

nano /etc/dhclient.conf

Add the following:

ignore domain-name, domain-name-servers;
append dhcp-lease-time 86400;
send host-name "cappuccino";
prepend domain-name-servers 127.0.0.1;
prepend domain-name "office.lan";

And now adjust the DHCP lease daemon:

nano /etc/dhcpleased.conf

Add this:

interface em0 {
        ignore dns
}

Manually hammer /etc/revolv.conf

Note, that I didn't have much luck with this method, it seems like still the best thing to do is manually edit /etc/resolv.conf and then change the flags:

nano /etc/resolv.conf

And add this:

nameserver 127.0.0.1
lookup file bind

And lock the file:

chflags uchg /etc/resolv.conf

This can be reversed with:

chflags nouchg /etc/resolv.conf

References