OpenBSD - Spam

In the past I have used SpamAssassin to manage spam filtering. To be honest I was never completely satisfied with it. Beyond blocking from known deny lists, it applies some analysis to each email and produces a score. You can choose to drop mails over a certain score - but if you do you risk dropping legitimate email. If you can't stomach that, you can send everything over a certain score to a Junk folder.

In my quest to stick closely to vanilla OpenBSD I decided this time around to follow a different approach and use spamd instead. Spamd works by presenting a fake SMTP server to interact with incoming requests. A request is either:

  • Allowlisted - in which case it gets to talk to the real OpenSMTPD daemon.
  • Greylisted - the client is given a temporary error and allowlisted if it tries again within a reasonable time (something spammers usually won't bother with).
  • Denylisted - the client is on a known spammer list - spamd will throttle the connection to one character per second and try to keep the connection open as long as possible - wasting as much of the spammers time and resources as possible.

One of the reasons to use OpenBSD built-in tooling is they are pleasingly tightly coupled. So spamd is driven in part by pf firewall rules:

pass in on egress proto tcp to any port smtp divert-to 127.0.0.1 port spamd
pass in on egress proto tcp from to any port smtp
pass in log on egress proto tcp from to any port smtp
pass out log on egress proto tcp to any port smtp


Where the nospamd and spamd-white tables are automatically populated by spamd.

Getting back at the spammers by clogging up their clients is extremely satisfying, made all the more enjoyable by examining the response codes spamd returns to the clients:

250 Hello, spam sender. Pleased to be wasting your time.
250 You are about to try to deliver spam. Your time will be spent, for nothing.
250 This is hurting you more than it is hurting me.
220 glad you want to burn more CPU cycles on your spam

OpenBSD - Mail Server

The utopian view we had of the Internet in the '90s - as a free, open, and democratic playground where information could be freely published by anyone - faces many challenges today. For the dream to stay alive, it must remain possible and practical for an individual to host their own web and mail servers.

Since web serving is trivial on OpenBSD using the built in httpd, there's little point documenting my configuration here. Although I will acknowledge that the rise of Let's Encrypt and similar services has made web self-hosting much more accessible.

When choosing to host your own mail you must face one stark reality - you might lose mail. In fact this is the reason I abandoned self-hosting in the past - it's all fun and games until you're waiting to hear back about a job application! With that in mind I decided to start with a domain which I semi-abandoned years ago: swproductions.co.uk.

In the past I have used sendmail or Postfix, but the dream is always to use the base tools provided by OpenBSD since they are secure, simple, and well integrated. With that in mind, I use OpenSMTPD.

For me the basic configuration is very straightforward since I won't have any virtual users - I just need to deliver mail to a single local account:

# configure TLS
pki "mail" key "/etc/ssl/private/home.kovkins.uk.key"
pki "mail" cert "/etc/ssl/home.kovkins.uk.fullchain.pem"

table aliases file:/etc/mail/aliases

# this is the default anyway
listen on socket
# listen on all interfaces port 25 with tls
listen on em0 tls pki "mail"
listen on lo tls pki "mail"

action "local_mail" maildir "%{user.directory}/.mail" alias

match from any for domain "swproductions.co.uk" action "local_mail"

# Needed to allow local routing of eg. root@home.kovkins.uk
match from local for local action "local_mail"


The configuration sets up pki settings, declares an alias table, and sets which interfaces to listen on. Then there are actions and matches. Actions declare what to do with a mail, and matches select which mails should be handled with which actions.

The complication came when I wanted to add two virtual users on another domain for whom mail would be forwarded to a Gmail address:

# Rotate every ~6 months
srs key "fx6o4WsA1AFoD2X2yzURsnNYRx1EvAjal6yFxT8C"
# When rotating, replace backup with the old key above.
srs key backup "sLXTf6CAEe7LwilX6D4C8Q6Mu7o4Hl8Jmtfz42x5"

table addresses { user1@jenkins.je, user2@jenkins.je }
table forwards { user1=address1@gmail.com, user2=address2@gmail.com }

action "relay" relay srs
action "aliasedrelay" forward-only virtual

# apply forwarding
match from any for rcpt-to action "aliasedrelay"
match from local for any action "relay"

Of course, now it seems remarkably straightforward, but a missing "from any" sent me down a rabbit hole which led me to briefly believe what I wanted to achieve wasn't possible.

BeFibre

Up until my mid-twenties there was never enough bandwidth. Dial-up obviously didn't cut it. ADSL was an improvement but the asymmetric bandwidth, along with sharing with other household members (in some cases, other tech minded students), left me still starving for bandwidth. Eventually Fibre To The Cabinet (FTTC) arrived and I stopped caring about bandwidth - it was good enough. Probably this went hand in hand with no longer using BitTorrent, not living with other people, etc. I settled in to paying BT £39/month for ~67 Mbps (still asymmetric).

One day a leaflet came through the door for BeFibre offering Fibre To The Premise (FTTP). I didn't need the bandwidth but I felt my teenage self would be livid at the thought of me passing up a fibre connection - plus it only costs £25/month for 500 Mbps (finally symmetric!).

BeFibre provide a Linksys MX4000 series router. This is a seriously flawed device. Firstly Linksys try to encourage you to manage the router through a mobile app for which you have to create a Linksys account. Secondly, the router's bridge mode does not work. It works fine up until a reboot at which point it just won't pass packets across the WAN/LAN interface.

We can do better.

My colleague Steve gave me a tip about Protectli devices. I bought the FW2B which provides two gigabit ethernet interfaces, 8GB ram, 120GB SSD. I have installed OpenBSD on it and use it as a router, firewall, DNS server, DHCP server, mail server, web server, and VPN server. I will detail the configuration in another post.

IMG_0717

The ONT presents an ethernet interface through which BeFibre offers a CGNAT IPv4 address via DHCP (with a 5 minute lease). In my experience you do not need to clone the Linksys MAC address if you choose to use your own hardware.

BeFibre also offer a static IPv4 address for an additional £4/month. In this case you do need to clone the Linksys MAC address in order for the DHCP server to assign you the static address.