Howto configure OpenBSD 4.3 as server-gateway-httpd-dhcpd-and-so-on

Disclaimer: This documentation could be useful if you plan to install OpenBSD on an old machine as a server-gateway-and-so-on , it's only my own notes from my personal experience. RTFM is your best friend. Some information here may burn your drive, eat your kitten, or make your daughter listen to tokyo hotel at full volume. Use at your own risk.

Some history: this doc was written after the hard disk of spud, my good'old Celeron 400 (and also my first pee-cee, bought in 1999), decided to die after 8 years of good and loyal services, running as a gateway since 2003 using various OS. I then had to replace it by lizzy, a nice Sun Blade 100 already running a stock -CURRENT and formerly used to build ports. A first version of this doc (french only) written during my first installation of OpenBSD on spud is still available here for the nostalgic.

Why OpenBSD ? Because it's nice, well documented, fights for open-source software and against evil blobs, and has numerous advantages among some GNU/Linux distribution around here (hints: pf, manpages, "shut up and hack" motto). And since i'm running it on all my workstations/laptops it seems i'm quite happy with it.

For the basesystem installation, please refer to the Official FAQ, it's a must-read.
Some other interesting links with valuable information :

This document will show some configuration file fragments, or sometimes even plain diffs against stock configuration.

The rest of this document is split in various sections, one by aspect/daemon configured :

Basic network configuration

My ISP is Free, and provides me the wonderful Freebox with a static IP, configured by DHCP. My Blade 100 has a builtin gem(4), so to have Internet access it's only a matter of configuring /etc/hostname.gem0, and setting the full hostname of lizzy in /etc/myname (normally, this is done during installation).

lizzy:~/ $cat /etc/hostname.gem0
dhcp NONE NONE NONE
If you don't want to reboot, just run dhclient gem0 (it will populate resolv.conf), and then test DNS resolution and Internet access.
lizzy:~/ $sudo dhclient gem0
DHCPREQUEST on gem0 to 255.255.255.255 port 67
DHCPACK from 82.245.140.254
bound to 82.245.140.102 -- renewal in 302400 seconds.
lizzy:~/ $cat /etc/resolv.conf
nameserver 212.27.54.252
nameserver 212.27.53.252
lookup file bind
lizzy:~/ $ifconfig gem0
gem0: flags=8863 mtu 1500
        lladdr 00:03:ba:0b:7c:e1
        groups: egress
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet6 fe80::203:baff:fe0b:7ce1%gem0 prefixlen 64 scopeid 0x1
        inet 82.245.140.102 netmask 0xffffff00 broadcast 82.245.140.255
lizzy:~/ $ping www.openbsd.org
PING www.openbsd.org (129.128.5.191): 56 data bytes
64 bytes from 129.128.5.191: icmp_seq=0 ttl=239 time=221.309 ms
--- www.openbsd.org ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 221.309/221.309/221.309/0.000 ms

Internet access for everyone!

Now that i have Internet access on lizzy, i want to enable NAT to allow my other computers to use lizzy as their Internet Gateway. It's quite simple:

But there is a caveat with the current setting: i don't have DNS resolution on local network hosts. It's the perfect time to configure named as a caching DNS server for the local network.

Named: a caching DNS server

I only made one simple modifications to the standard named.conf: allowing only clients from the LAN to use this server.

lizzy:~/ $sudo diff -u var/named/etc/named.conf /var/named/etc/named.conf 
--- var/named/etc/named.conf    Fri May  2 13:45:46 2008
+++ /var/named/etc/named.conf   Sun May 11 23:21:52 2008
@@ -10,7 +10,7 @@
 // the IPv6 localhost address.
 //
 acl clients {
-       localnets;
+       10.246.200.0/24;
        ::1;
 };
Then, enable named in rc.conf.local by adding a single line: named_flags="". It will listen on UDP and TCP ports 53. Now named can be manually run. As a sidenote, i added two lines to lizzy's dhclient.conf to use its own DNS server when performing local DNS searches (these lines are added to resolv.conf when running dhclient on the external interface):
prepend domain-name-servers 10.246.200.1;
prepend domain-name "fr.homeunix.org";
Now your DNS server works, but you still have to configure local hosts to use it in resolv.conf... now enters dhcpd!.

Network autoconfiguration with dhcpd

dhcpd is also provided by the basesystem, and is a powerful DHCP server. Here's an excerpt of my own configuration (i use a little range for potential foreign DHCP clients, my own machines all have a fixed IP address.)
shared-network LOCAL-NET {
    # send domain name and DNS servers to requesting clients
    option domain-name "fr.homeunix.org";
    option domain-name-servers 10.246.200.1, 252.27.53.252, 252.27.54.252 ;

    subnet 10.246.200.0 netmask 255.255.255.0 {
        option routers 10.246.200.1;
        range 10.246.200.30 10.246.200.40;
    }
}

# declare some fixed hosts with the corresponding MAC address
group {
    use-host-decl-names on;
    host renton {
        hardware ethernet 00:08:a1:33:2e:ac;
        fixed-address 10.246.200.10;
    }
    host diane {
        hardware ethernet 00:09:5b:22:e2:a1;
        fixed-address 10.246.200.13;
    }
    host foune {
        hardware ethernet 00:18:84:1a:44:f4;
        fixed-address 10.246.200.15;
    }
    host sickboy-wlan {
        hardware ethernet 00:13:d4:04:18:69;
        fixed-address 10.246.200.16;
    }
}
Then, enable dhcpd in rc.conf.local by adding dhcpd_flags="". You also have to specify the interface dhcpd will listen on in /etc/dhcpd.interfaces, or you can also directly specify it in dhcpd_flags. You can then test it by running dhclient on local hosts:
May 13 18:29:25 lizzy dhcpd: DHCPDISCOVER from 00:08:a1:33:2e:ac via rl0
May 13 18:29:25 lizzy dhcpd: DHCPOFFER on 10.246.200.10 to 00:08:a1:33:2e:ac via rl0
May 13 18:29:25 lizzy dhcpd: DHCPREQUEST for 10.246.200.10 from 00:08:a1:33:2e:ac via rl0
May 13 18:29:25 lizzy dhcpd: DHCPACK on 10.246.200.10 to 00:08:a1:33:2e:ac via rl0
Of course resolv.conf will be correctly populated on local hosts:
renton:~/ $cat /etc/resolv.conf
search fr.homeunix.org
nameserver 10.246.200.1
nameserver 252.27.53.252
nameserver 252.27.54.252
lookup file bind
So now we have network configuration for the LAN, but maybe we want to enable DNS queries between local hosts, avoiding filling /etc/hosts on each host. Let's configure named to also handle the local DNS zone.

Named: also a full-featured DNS server

Here, i have a DNS zone for all the machines on my local network, and each machine has its own hostname. But how can i know that renton.fr.homeunix.org refers to 10.246.200.10 and vice-versa ? For this, i added two zone files in /var/named/master, one for the forward mapping, and one for the reverse mapping.
First, these lines have to be added to named.conf. They link a zone to its zone description file (here fr.homeunix.org and 200.246.10.in-addr.arpa for the reverse zone).

zone "fr.homeunix.org" {
    type master;
    file "master/fr.homeunix.org";
};

zone "200.246.10.in-addr.arpa" {
    type master;
    file "master/200.246.10.in-addr.arpa";
};
Here, the description of the zone, and some explanations: the NS line states that lizzy (also known as fr.homeunix.org on the Internet) is the authoritative server for the zone. Each machine is then described by a A record, linking a hostname to an IP address. I also added a TXT field, to allow queries host -t TXT lizzy which returns lizzy.fr.homeunix.org descriptive text "Main gateway and server"
$TTL 3d

@    IN    SOA    fr.homeunix.org. root (
                  1    ; serial
                  1h   ; refresh
                  30m  ; retry
                  7d   ; expiration
                  1h ) ; minimum

        NS    lizzy
lizzy   A     10.246.200.1
        TXT   "Main gateway and server"

renton  A     10.246.200.10
        TXT   "Desktop"

diane   A     10.246.200.13
        TXT   "File server"

begbie  A     10.246.200.14
        TXT   "Work Laptop"

foune   A     10.246.200.15
        TXT   "wireless router"

sickboy-wlan   A    10.246.200.16
        TXT   "Bed Laptop (wifi)"

begbie-wlan    A    10.246.200.17
        TXT    "Work Laptop (wifi)"

spup    A     10.246.200.18
        TXT   "Old server"

newt    A     10.246.200.21
        TXT   "SUN Ultra 60 SMP"
With this setting, i can now query my DNS server like this (or use dig/host):
renton:~/ $nslookup diane
Server:   10.246.200.1
Address:  10.246.200.1#53

Name:     diane.fr.homeunix.org
Address:  10.246.200.13
But what if i only have an IP address and want to know the corresponding hostname ? I need a reverse zone description, doing the exact opposite of the previous description.
$TTL 3d

@    IN    SOA    fr.homeunix.org. root (
                  1    ; serial
                  1h   ; refresh
                  30m  ; retry
                  7d   ; expiration
                  1h ) ; minimum

              NS    lizzy.fr.homeunix.org.
1       IN    PTR   lizzy.
10      IN    PTR   renton.
13      IN    PTR   diane.
14      IN    PTR   begbie.
15      IN    PTR   foune.
16      IN    PTR   sickboy-wlan.
17      IN    PTR   begbie-wlan.
18      IN    PTR   spud.
21      IN    PTR   newt.
I reload named again (either with rndc if configured or by restarting it), and now i can query it like this:
renton:~/ $nslookup diane
Server:   10.246.200.1
Address:  10.246.200.1#53

Name:     diane.fr.homeunix.org
Address:  10.246.200.13

renton:~/ $host begbie
begbie.fr.homeunix.org has address 10.246.200.14
That's all for DNS service. In 30 minutes, the box is up and running, and serving NAT, DHCP and DNS services to the local network.

Fetch your inboxes with fdm

Now, external e-mail fetching and sorting... before, i used the mandatory couple fetchmail+procmail, but i recently discovered fdm, which nicely does the trick. Here's my sample commented configuration file, which is only readable by my user.

lizzy:~/ $cat .fdm.conf
set default-user "landry"
action "keep" keep
action "drop" drop

# i use Maildir format, let's declare all target folders.
$path = "%h/Maildir"
action "inbox"          maildir "${path}"
action "junk"           maildir "${path}/.Spam"
action "free"           maildir "${path}/.Free"
action "fws"            maildir "${path}/.FWS"
action "homeunix"       maildir "${path}/.Homeunix"
action "laposte"        maildir "${path}/.Laposte"
action "hand-thorigne"  maildir "${path}/.ml.hand-thorigne"
action "sme-security"   maildir "${path}/.ml.Sme-security"

# my secondary inbox
$path2 = "%h/Maildir-GCU"
action "inbox-gcu"              maildir "${path2}/.gcu"
action "sysadmin"               maildir "${path2}/.sysadmin"
action "openbsd-ports"          maildir "${path2}/.obsd-ports"
action "openbsd-ports-changes"  maildir "${path2}/.obsd-ports-cvs"
action "openbsd-source-changes" maildir "${path2}/.obsd-src-cvs"

# this action will send the e-mail on the standard input of dspam
# which will analyse it, flag it a spam or ham, and rewrite it on
# its stdout for processing.
action "dspam" rewrite "/usr/local/bin/dspam --client --user landry
--mode=toe --deliver=innocent,spam --stdout"

# declaration of the accounts, and how to fetch them
account "gcu" imaps
    server "xxx.gcu-squad.org"
    user "xxx"
    pass "xxx"

account "free" pop3
    server "pop.free.fr"
    user "xxx"
    pass "xxx"

account "laposte" pop3
    server "pop.laposte.net"
    user "xxx"
    pass "xxx"

account "fws" pop3s
    server "xxx.firewall-services.com"
    user "xxx"
    pass "xxx"

# this account is special: it analyses messages fdm receives on its
# stdin (will be used by postfix), and is disabled from the list of
# accounts to fetch.
account "stdin" disabled stdin

# sort @openbsd.org mailing list and send them to the corresponding
# action, which will store the e-mail in the right folded. %1
# corresponds to the () part of the regexp.
match "^Sender:[ \t]*owner-([a-z-]*)@openbsd\\.org" in headers {
    match all action "openbsd-%1"
}

# commented atm, this action will directly drop mail flagged as spam
# with a confidence of at least 0.8.
#match "^X-DSPAM-Confidence: 0.[89].*" in headers action "drop"

# store already flagged spam (by another spam filter) into junk
match "^X-DSPAM-Result: Spam" in headers action "junk"

# send each e-mail smaller that 256k to the dspam action, and 'continue'
# processing after dspam returned the processed e-mail.
match size < 256k and accounts { "stdin" "fws" "free" "laposte" } action
"dspam" continue

# store newly flagged spam (by my own spam filter) into junk
match "^X-Spam-Status: Yes" or "^X-Spam-Flag: YES" or "^X-DSPAM-Result:
Spam" in headers action "junk"

# store e-mail not catched by any other rule into the default inbox for
# this account
match account "gcu" action "inbox-gcu"


# for each account, sort e-mail in the right inbox using regexps on
# headers
match account "stdin" {
    match "^List-Id:.*hand-thorigne\\.googlegroups\\.com" in headers
action "hand-thorigne"
    match "^(To|Cc):.*landry@fr\\.homeunix\\.org" in headers action
"homeunix"
}

match account "free" and "^(To|Cc):.*landry\\.breuil@free\\.fr" in
headers action "free"

match account "laposte" and "^(To|Cc):.*landry\\.breuil@laposte\\.net"
in headers action "laposte"

match account "fws" {
    match "^(To|Cc):.*admin@contribs\\.org" in headers action "fws"
    match "^(To|Cc):.*security@.*contribs\\.org" in headers action
"sme-security"
    match "^(To|Cc):.*landry.*@.*firewall-services\\.com" in headers
action "fws"
}

# store e-mail not catched by any other rule into the default inbox
match all action "inbox"
See, its configuration is really sexy !! To see if everything's fine, test it with fdm -nvv .fdm.conf. Then, you can tell it to fetch various accounts verbosely with fdm -v fetch, or only poll for new messages with fdm poll.
Once you're happy with your configuration, launch fdm through your user crontab like this:
*/10 * * * * /usr/local/bin/fdm -v fetch 2>&1 | /usr/bin/tee -a ~/fdm.log
Now, your e-mail is fetched and sorted. Let's access it remotely (though you can access it locally with the excellent mutt).

Access your e-mail using IMAPS

For this, i was previously using courier-imap, but i recently found dovecot to be simpler and lighter.
After installation with pkg_add, a MESSAGE shows how to create a SSL certificate needed by IMAPS/POPS protocols. I edited /etc/ssl/dovecot-openssl.cnf with my personal information, and ran /usr/local/sbin/dovecot-mkcert.sh.

Now, let's configure it in /etc/dovecot.conf. Here's the only modification i made to the original standard configuration:

Why a namespace ? Because i have two distinct Maildirs in my homedir, and want to access both through dovecot. I only have to set my MUA to use 'GCU' folder instead of the empty default to access the secondary Maildir, this is quite handy.
lizzy:~/ $diff -u /usr/local/share/examples/dovecot/dovecot-example.conf
/etc/dovecot.conf 
--- /usr/local/share/examples/dovecot/dovecot-example.conf      Mon Apr
28 06:46:14 2008
+++ /etc/dovecot.conf   Mon May 12 12:23:14 2008
@@ -20,6 +20,7 @@
 # Protocols we want to be serving: imap imaps pop3 pop3s
 # If you only want to use dovecot-auth, you can set this to "none".
 #protocols = imap imaps
+protocols = imaps
 
 # IP or host address where to listen in for connections. It's not
 # currently
 # possible to specify multiple addresses. "*" listens in all IPv4
 # interfaces.
@@ -61,6 +62,7 @@
 # Log file to use for error messages, instead of sending them to
 # syslog.
 # /dev/stderr can be used to log into stderr.
 #log_path = 
+log_path = /var/log/dovecot.log
 
 # Log file to use for informational and debug messages.
 # Default is the same as log_path.
@@ -209,6 +211,7 @@
 # 
 #
 #mail_location = 
+mail_location = maildir:~/Maildir
 
 # If you need to set multiple mailbox locations or want to change
 # default
 # namespace settings, you can do it by defining namespace sections.
@@ -250,6 +253,18 @@
    # prefixes "~/mail/", "~%u/mail/" and "mail/".
    #hidden = yes
 #}
+
+namespace private {
+  separator = /
+  prefix =
+  inbox = yes
+}
+
+namespace private {
+  separator = /
+  prefix = GCU/
+  location = maildir:~/Maildir-GCU
+}
 
 # Group to enable temporarily for privileged operations. Currently this
 # is
 # used only for creating mbox dotlock files when creation fails for
 # INBOX.
And finally, as adviced by the MESSAGE file, i add the following lines to /etc/rc.local to launch dovecot upon boot.
if [ -x /usr/local/sbin/dovecot ]; then
    echo -n ' dovecot';   /usr/local/sbin/dovecot
fi
Now, my Maildirs can be accessed from any host using a MUA supporting IMAPS protocol. But what if i want to receive e-mail on my own domain, and even send e-mail using my own server and not the one provided by my ISP ?

Send and receive e-mail with postfix

I know sendmail is provided with the base installation, but i'm more used to Postfix's syntax. I use it without flavors, but there are various combinations of packages available with sasl2 enabled for SMTP authentication, or with LDAP/MySQL/PostgreSQL/BDB backends for user lookups. After installation, a MESSAGE file is here to show how to configure, enable and run postfix "the OpenBSD way".

So let's have a look at my simple configuration (comments after the diff) :

--- main.cf.package     Sun Jul  6 23:36:40 2008
+++ main.cf     Wed May 14 21:24:34 2008
@@ -72,7 +72,7 @@
 # from gethostname(). $myhostname is used as a default value for many
 # other configuration parameters.
 #
-#myhostname = host.domain.tld
+myhostname = fr.homeunix.org
 #myhostname = virtual.domain.tld
 
 # The mydomain parameter specifies the local internet domain name.
@@ -263,6 +263,7 @@
 #mynetworks = 168.100.189.0/28, 127.0.0.0/8
 #mynetworks = $config_directory/mynetworks
 #mynetworks = hash:/etc/postfix/network_table
+mynetworks = 10.246.200.0/24, 127.0.0.0/8
 
 # The relay_domains parameter restricts what destinations this system
 # will
 # relay mail to.  See the smtpd_recipient_restrictions description in
@@ -315,6 +316,8 @@
 #relayhost = uucphost
 #relayhost = [an.ip.add.ress]
 
+relayhost = smtp.free.fr
+
 # REJECTING UNKNOWN RELAY USERS
 #
 # The relay_recipient_maps parameter specifies optional lookup tables
@@ -382,7 +385,7 @@
 # "postfix reload" to eliminate the delay.
 #
 #alias_maps = dbm:/etc/aliases
-#alias_maps = hash:/etc/aliases
+alias_maps = hash:/etc/postfix/aliases
 #alias_maps = hash:/etc/aliases, nis:mail.aliases
 #alias_maps = netinfo:/aliases
 
@@ -415,7 +418,7 @@
 # "Maildir/" for qmail-style delivery (the / is required).
 #
 #home_mailbox = Mailbox
-#home_mailbox = Maildir/
+home_mailbox = Maildir/
  
 # The mail_spool_directory parameter specifies the directory where
 # UNIX-style mailboxes are kept. The default setting depends on the
@@ -445,6 +448,7 @@
 #
 #mailbox_command = /some/where/procmail
 #mailbox_command = /some/where/procmail -a "$EXTENSION"
+mailbox_command = /usr/local/bin/fdm -l -m -a stdin fetch
 
 # The mailbox_transport specifies the optional transport in master.cf
 # to use after processing aliases and .forward files. This parameter
@@ -520,7 +524,7 @@
 #
 # For details, see "man header_checks".
 #
-#header_checks = regexp:/etc/postfix/header_checks
+header_checks = regexp:/etc/postfix/header_checks
 
 # FAST ETRN SERVICE
 #
@@ -544,7 +548,7 @@
 # You MUST specify $myhostname at the start of the text. That is an
 # RFC requirement. Postfix itself does not care.
 #
-#smtpd_banner = $myhostname ESMTP $mail_name
+smtpd_banner = $myhostname ESMTP $mail_name
 #smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
 
 # PARALLEL DELIVERY TO THE SAME DESTINATION
@@ -652,3 +656,33 @@
 # readme_directory: The location of the Postfix README files.
 #
 readme_directory = /usr/local/share/doc/postfix/readme
+
+smtpd_tls_cert_file = /etc/postfix/ssl/server.crt
+smtpd_tls_key_file = /etc/postfix/ssl/server.key
+smtpd_tls_CAfile = /etc/postfix/ssl/server.crt
+smtpd_tls_CApath = /etc/postfix/ssl
+smtpd_tls_loglevel = 1
+smtpd_use_tls = yes
+smtpd_tls_received_header = yes
+
+transport_maps = hash:/etc/postfix/transport.my
+
+smtpd_helo_required = yes
+smtpd_sender_restrictions = reject_unknown_address
+smtpd_recipient_restrictions=
+       permit_mynetworks,
+       permit_sasl_authenticated,
+       reject_invalid_hostname,
+       reject_unauth_destination,
+       reject_non_fqdn_sender,
+       reject_non_fqdn_recipient,
+       reject_unknown_sender_domain,
+       reject_unknown_recipient_domain,
+       reject_rbl_client blackholes.easynet.nl,
+       reject_rbl_client cbl.abuseat.org,
+       reject_rbl_client proxies.blackholes.wirehub.net,
+       reject_rbl_client bl.spamcop.net,
+       reject_rbl_client dnsbl.njabl.org,
+       reject_rbl_client list.dsbl.org,
+       reject_rbl_client multihop.dsbl.org,
+       permit

Now that it's correctly configured, we have to enable it through the provided script /usr/local/sbin/postfix-enable which will 'hook' postfix in the system in place of sendmail using /etc/mailer.conf. Finally, we can launch it with /usr/local/sbin/postfix start, and check that it is running by sending an e-mail to an user of the server using an external account, and also in the other direction. Watching /var/log/maillog is really helpful too.

Serve a simple HTML website

This website is served by the stock httpd shipped in basesystem. Enabling it is just a matter of adding httpd_flags="" to /etc/rc.conf.local. As the website is plain HTML at the moment, it's easy, but things are funnier if you start playing with perl CGIs or PHP websites, you have to fill a bit the chroot.

I also made some modifications to the standard httpd.conf provided with base install, basically setting the server admin address, relaxing AllowOverride to permit the use of .htaccess, and combining all the logs with referer and user agent into the unique access_log file :

--- ./var/www/conf/httpd.conf   Fri Jul  4 03:59:35 2008
+++ /var/www/conf/httpd.conf    Sun Jul  6 14:26:58 2008
@@ -341,7 +341,7 @@
 # e-mailed.  This address appears on some server-generated pages, such
 # as error documents.
 #
-ServerAdmin you@your.address
+ServerAdmin me@my.fqnd
 
 #
 # ServerName allows you to set a host name which is sent back to
 # clients for
@@ -403,7 +403,8 @@
 # override. Can also be "All", or any combination of "Options",
 # "FileInfo", 
 # "AuthConfig", and "Limit"
 #
-    AllowOverride None
+    AllowOverride All
+#None
 
 #
 # Controls who can get stuff from this server.
@@ -566,7 +567,7 @@
 # define per- access logfiles, transactions will be
 # logged therein and *not* in this file.
 #
-CustomLog logs/access_log common
+# CustomLog logs/access_log common
 
 #
 # If you would like to have agent and referer logfiles, uncomment the
@@ -579,7 +580,7 @@
 # If you prefer a single logfile with access, agent, and referer
 # information
 # (Combined Logfile Format) you can use the following directive.
 #
-#CustomLog logs/access_log combined
+CustomLog logs/access_log combined
 
 #
 # Optionally add a line containing the server version and virtual host

Protect local network with PacketFilter

PacketFilter is one of the numerous killer feature of OpenBSD. Valuable documentation has been written for it, other *BSD use it too, and it keeps being optimized by its developers. To use it, you just have to fill /etc/pf.conf, enable it permanently in /etc/rc.conf.local adding pf=YES (or temporarly using pfctl -e -f /etc/pf.conf). Here's my pf.conf, not deriving that much from the provided default, comments inline. And remember, with pf the last matching rules wins if you don't use quick keyword.

# my network external and internal interfaces
ext_if="gem0"
int_if="rl0"

# the services i will allow
services= "{ http, smtp, imaps }"

# some aliases from well-known-hosts
begbie = "131.254.13.44"
sickboy = "10.246.200.16"

# a permanent table of blocked hosts
table  persist

# we don't care about loopback interface
set skip on lo

scrub in

# nat the local network hosts to the internet
nat on $ext_if from !($ext_if) -> ($ext_if:0)

# redirect traffic from a certain ip to another host (ISP tv-over-ip)
rdr pass on $ext_if proto udp from 212.27.38.253 -> $sickboy

# block and forget about permanently blocked hosts
block in quick from 

# default policy : we block every incoming traffic
block in

# let everything coming from and to local network pass
pass quick on $int_if no state
antispoof quick for $int_if

# allow all outgoing traffic
pass out

# allow http/smtp/imaps services to work on the external interface
pass in on $ext_if proto tcp to ($ext_if) port $services

# allow pings on the external interface
pass in on $ext_if inet proto icmp to ($ext_if) icmp-type { echorep, echoreq, timex, unreach }

# allow ssh on the external interface, but add the client to blocked
# table if it tries to connect more than two times in ten seconds
pass in on $ext_if inet proto tcp to ($ext_if) port ssh keep state (max-src-conn-rate 2/10, overload  flush)

# explicitely allow unblockable ssh from a trusted machine
pass in on $ext_if inet proto tcp from $begbie to ($ext_if) port ssh
That's it, not that complicated to read and understand.

Fight against spam

TODO

Synchronize clocks using NTP

OpenBSD provides OpenNTPD in its basesystem to synchronize system clock using NTP protocol, let's use it. Configuration is done in /etc/ntpd.conf, you can use default settings which will select the NTP server in a pool of servers, or choose to specify one. Here's my configuration:

lizzy:~/ $cat /etc/ntpd.conf
# $OpenBSD: ntpd.conf,v 1.8 2007/07/13 09:05:52 henning Exp $
# sample ntpd configuration file, see ntpd.conf(5)

# Addresses to listen on (ntpd does not listen by default)
listen on 10.246.200.1

# sync to a single server
server ntp.univ-lyon1.fr

# use a random selection of 8 public stratum 2 servers
# see http://support.ntp.org/bin/view/Servers/NTPPoolServers
# servers pool.ntp.org
Not only ntpd will synchronize my server's clock, but it will also listen on the local network (UDP port 123) for NTP queries from my other hosts. To enable ntpd at startup, just add the following lines to /etc/rc.conf.local:
ntpd=YES
ntpd_flags="-s"
I decided to tell ntpd to immediatly set time at startup. Now clients on my local network can use server lizzy in their own /etc/ntpd.conf and enable ntpd, they will be synchronized too.

Sharing /usr/{src,ports} with NFS

If you want to develop code for OpenBSD, or port some software to our ports-tree, it's quite handy to use the bundled NFS server to share the ports-tree and the source-tree among several machines of various architectures. Remember, portable code is always better, so test it on various arches (at least i386 and sparc64 if possible..).

To use the nfs server, you need to refer to those manpages : nfsd(8), mountd(8), exports(5) and portmap(8). Enabling nfsd is done by adding portmap=YES and nfs_server=YES in /etc/rc.conf.local and configuring the exports in /etc/exports :

/usr -maproot=root -alldirs renton newt
Here, i export the whole /usr (careful, if you want to use maproot you have to export the root of the filesystem, otherwise it won't work) to hosts renton and newt. -alldirs is here because i want the remote hosts to be able to mount subdirectories of this filesystem. And -maproot=root is here to allow root on remote hosts to be mapped to local root user, this is needed for ports builds.

Now, to test, reboot the server (or manually run portmap, mountd and nfsd -tun 4), and on the clients run mount_nfs lizzy:/usr/ports /usr/ports. It should just work !. You can finally add the following lines to /etc/fstab :

lizzy:/usr/src /usr/src nfs rw,nosuid,noatime 0 0
lizzy:/usr/ports /usr/ports nfs rw,nosuid,noatime 0 0

Use IPv6 across the internet

My ISP only provides me a /64 subnet, which is not really usable if i want to use auto-configuration on my gateway, so i decided to ask for a tunnel and a /48 subnet to SixXS tunnel broker. It's fast, reliable, and has a lot of PoP across europe. Their documentation is really good.

To use IPv6 on my gateway first, i had to configure a gif(4) tunnel. This is done easily through a /etc/hostname.gif0 file :
tunnel my.public.ip.v4 ipv4.of.sixxs.pop
inet6 my:local:ipv6:endpoint:address 128
dest sixxs:remote:pop:ipv6:endpoint:address
!/sbin/route add -inet6 default sixxs:remote:pop:ipv6:endpoint:address
Run sh /etc/netstart gif0, and you're done !
lizzy:~/ $ifconfig gif0
gif0: flags=8051 mtu 1280
        groups: gif egress
        physical address inet 82.245.140.102 --> 212.100.184.146
        inet6 fe80::203:baff:fe0b:7ce1%gif0 ->  prefixlen 64 scopeid 0x7
        inet6 2001:6f8:202:2d0::2 -> 2001:6f8:202:2d0::1 prefixlen 128
You can then try ping6 www.kame.net and traceroute www.kame.net. Btw it needs some adjustments to PF configuration:
# allow ipv6 packets encapsuled into ipv4 packets to come from sixxs PoP
pass in on $ext_if inet proto ipv6 from $sixxs_pop4 to $ext_if

# allow incoming ping6 packets
pass in on $tun_if inet6 proto icmp6 all icmp6-type { echoreq, echorep }
You may also need to allow more incoming ssh/www traffic on inet6 address family, according to your needs.

But you may also want to distribute IPv6 to your local network. This is done by first configuring an IPv6 on the internal interface, taken in the subnet assigned to you by the tunnel broker:

lizzy:~/ $cat /etc/hostname.rl0
inet 10.246.200.1 255.255.255.0 NONE
inet6 2001:6f8:1410::1 64
lizzy:~/ $sh /etc/netstat rl0 && ifconfig rl0
rl0: flags=8843 mtu 1500
        lladdr 00:e0:4c:03:10:ed
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet 10.246.200.1 netmask 0xffffff00 broadcast 10.246.200.255
        inet6 fe80::2e0:4cff:fe03:10ed%rl0 prefixlen 64 scopeid 0x2
        inet6 2001:6f8:1410::1 prefixlen 64
Now that you have an IPv6 on the internal side, you can distribute IPv6 addresses to the local network using rtadvd(8). It is manually started by using rtadvd rl0, or upon boot if rtadvd_flags="rl0" is added to /etc/rc.conf.local. You also have to set the net.inet6.ip6.forwarding sysctl to 1.

Now, on the local network clients, you only have to enable net.inet6.ip6.accept_rtadv sysctl, and run rtsol rl0 (don't forget to add rtsold_flags="rl0" to /etc/rc.conf.local to make this setting permanent). It should have been assigned an IPv6 address in the 2001:6f8:1410:: subnet. Normally, if PF is not blocking things, you should be able to access internet through IPv6, and see the kame.net dancing turtle. (wee!).. there should be a little more latency due to the gif tunnel, but this is the price to pay before full-IPv6.. Now, you can also play with AAAA records in your DNS, and configure a reverse zone for IPv6 addresses.

That's all folks ! Hope you enjoyed the ride..

OpenBSD.org