OpenBSD Router, 3rd draft
And here we go again. The problem with the previous configuration is that DNS doesn’t work: you can ping any IP address you like across the open internet, but URLs weren’t being resolved. That is, ping 1.1.1.1
works fine, but ping google.com
failed completely.
So this is a variation that focuses on unbound. The rest of the settings and architecture are included, because unbound does not exist in a vaccume - but they’re just a sideshow.
As before, we assume this is a fresh installation of OpenBSD 6.9 on a dedicated physical box which has separate ethernet ports for each subnet and the egress point.
We’re using another source: https://openbsdrouterguide.net/#dns-hijacking.
Looks like there’s a specific domain I should use for my local network, since I haven’t registered one properly: .home.arpa
. Guess that’s a holdover from the early days.
Some people recommend that you register a domain name and then use that internally on your LAN, and while that certainly works, it is not necessary at all. According to the RFC 8375 you should use the .home.arpa domain as this is meant to be used inside a small network, such as a home network.
network design
Nonstandard diagram, but might be a little less obtuse than the standard.
0.0.0.0/0
+-----------------------------+
| open internet |
+-+---------------------------+
|
|
| 123.12.23.2
+-+---------------------------+
| ISP-assigned router |
| device: em2 |
+-+---------------------------+
|
|
| 192.168.1.102
+-+---------------------------+
| firewall / router |
| (OpenBSD) |
+-+--+------------------------+
| |
| |
| | 10.0.1.1/24 +------------+-----------------------+
| | +------------------------+ | | |
| +--+ (insecure network) +---+ +--------+---------+ +----------+----------+
| | device: em0 | |wifi access points| |laptops, servers, etc|
| +------------------------+ +------------------+ +---------------------+
|
|
| 10.0.2.1/24 +------------+-----------------------+
| +------------------------+ | | |
+-----+ (secure network) +---+ +--------+---------+ +----------+----------+
| device: em1 | |wifi access points| |laptops, servers, etc|
+------------------------+ +------------------+ +---------------------+
Note, depending on the OpenBSD firewall/router box configuration, there can also be virtual machines inside that box which are connected to one or more of the subnets.
The router will have an ip address on each of the subnets; this is referred to as the ‘gateway address’, since the router is literally a gateway out of the sub-network. That IP address is usually the first in the available series: i.e., 100.100.1.1 and 100.100.2.1 in the two examples above.
I like having the wireless clients on the same subnet as the wired clients, but that’s my use case. It can be nearly as easy to put all the wifi APs on their own subnet.
router construction
Preliminaries.
echo 'net.inet.ip.forwarding=1' > /etc/sysctl.conf
echo 'dhcp' > /etc/hostname.em2
echo 'inet 10.0.0.1 255.255.255.0 10.0.0.255 description "secure network"' > /etc/hostname.em0
echo 'inet 10.0.1.1 255.255.255.0 10.0.1.255 description "insecure network"' > /etc/hostname.em1
DHCP (IP address assignment)
Start the dhcpd
daemon, and tell it which network device ports will need the dhcp service available.
rcctl enable dhcpd
rcctl set dhcpd flags em0 em1
/etc/dhcpd.conf
option domain-name "home.arpa";
subnet 10.0.0.0 netmask 255.255.255.0 {
option routers 10.0.0.1;
option domain-name-servers 10.0.0.1;
range 10.0.0.10 10.0.0.254;
}
subnet 10.0.1.0 netmask 255.255.255.0 {
option routers 10.0.1.1;
option domain-name-servers 10.0.1.1;
range 10.0.1.10 10.0.1.254;
}
PF (firewall)
/etc/pf.conf
secure = "em0"
insecure = "em1"
external = "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)
antispoof quick for { egress $secure $insecure }
block in quick on egress from <martians> to any
block return out quick on egress from any to <martians>
block all
pass out quick inet
# pass out on $external inet from $secure:network to any nat-to ($external)
# pass out on $external inet from $insecure:network to any nat-to ($external)
pass in on { $secure $insecure } inet
DNS
Enable the unbound
DNS daemon.
rcctl enable unbound
Create an unbound-specific log file.
mkdir /var/unbound/log
touch /var/unbound/log/unbound.log
chown -R root._unbound /var/unbound/log
chmod -R 774 /var/unbound/log
/var/unbound/etc/unbound.conf
server:
# Logging (default is no).
# Uncomment this section if you want to enable logging.
# Note enabling logging makes the server (significantly) slower.
# verbosity: 2
# log-queries: yes
# log-replies: yes
# log-tag-queryreply: yes
# log-local-actions: yes
# logfile: "/log/unbound.log"
# use-syslog: no
# log-time-ascii: yes
interface: 127.0.0.1
interface: 10.0.0.1
interface: 10.0.1.1
# Control who has access.
access-control: 0.0.0.0/0 refuse
access-control: ::0/0 refuse
access-control: ::1 allow
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/24 allow
access-control: 10.0.1.0/24 allow
# "id.server" and "hostname.bind" queries are refused.
hide-identity: yes
# "version.server" and "version.bind" queries are refused.
hide-version: yes
# Cache elements are prefetched before they expire to keep the cache up to date.
prefetch: yes
# Our LAN segments.
private-address: 10.0.0.0/16
# local domain
private-domain: home.arpa
# otherwise unbound tries to get DNS info from IPV6 addresses:
# "info: error sending query to auth server"
do-ip6: no
# save cached lookups for way longer than I should
# 3600 = 1 hour
# 86400 = 1 day
# 604800 = 1 week
cache-min-ttl: 604800
serve-expired: yes
# use an updated root hints file
root-hints: "/var/unbound/etc/named.cache"
# We want DNSSEC validation.
# auto-trust-anchor-file: "/var/unbound/db/root.key"
# Enable the usage of the unbound-control command.
remote-control:
control-enable: yes
control-interface: /var/run/unbound.sock
Nameserver
We want the router to use its own unbound DNS cache.
/etc/resolv.conf
nameserver 127.0.0.1
# nameserver 192.168.43.79
echo "nameserver 127.0.0.1" > /etc/resolv.conf
Problem is, this gets overwritten every time dhcp runs, because part of the dhcp protocol is a record of the server which provided the IP address. We have our own such server, and we want to use it instead.
/etc/dhclient.conf
interface "em2" {
ignore domain-name-servers;
}