[ comp1 ] ---+ | [ comp2 ] ---+--- [ switch ] --- em1 [ OpenBSD ] em0 --- [ internet ] | athn0 [ comp3 ] ---+ ))))) ((((( [ comp4 ]Replace the
em0
, em1
, and athn0
interface names as appropriate.
# echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf # echo 'inet autoconf' > /etc/hostname.em0 # or use a static IP # echo 'inet 192.168.1.1 255.255.255.0 192.168.1.255' > /etc/hostname.em1 # vi /etc/hostname.athn0Add the following, changing the mode/channel if needed:
media autoselect mode 11n mediaopt hostap chan 1 nwid AccessPointName wpakey VeryLongPassword inet 192.168.2.1 255.255.255.0OpenBSD defaults to allowing only WPA2-CCMP connections in HostAP mode. If support for older (insecure) protocols is needed, they must be explicitly enabled.
# rcctl enable dhcpd # rcctl set dhcpd flags em1 athn0 # vi /etc/dhcpd.confThe following dhcpd.conf(5) example also provides static IP reservations for a laptop and server based on their MAC addresses.
subnet 192.168.1.0 netmask 255.255.255.0 { option routers 192.168.1.1; option domain-name-servers 192.168.1.1; range 192.168.1.4 192.168.1.254; host myserver { fixed-address 192.168.1.2; hardware ethernet 00:00:00:00:00:00; } host mylaptop { fixed-address 192.168.1.3; hardware ethernet 11:11:11:11:11:11; } } subnet 192.168.2.0 netmask 255.255.255.0 { option routers 192.168.2.1; option domain-name-servers 192.168.2.1; range 192.168.2.2 192.168.2.254; }Any RFC 1918 address space may be specified here. The
domain-name-servers
line in this example specifies a local
DNS server that will be configured in a later section.
# vi /etc/pf.confA gateway configuration might look like this:
wired = "em1" wifi = "athn0" 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 $wired $wifi } 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 in on { $wired $wifi } inet pass in on egress inet proto tcp from any to (egress) port { 80 443 } rdr-to 192.168.1.2The ruleset's various sections will now be explained:
wired = "em1" wifi = "athn0"The wired and wireless interface names for the LAN are defined with macros, used to make overall maintenance easier. Macros can be referenced throughout the ruleset after being defined.
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 }This is a table of non-routable private addresses that will be used later.
set block-policy drop set loginterface egress set skip on lo0PF allows certain options to be set at runtime. The
block-policy
decides whether rejected packets should return
a TCP RST or be silently dropped.
The loginterface
specifies which interface should have packet
and byte statistics collection enabled.
These statistics can be viewed with the pfctl -si
command.
In this case, the egress
group is being used
rather than a specific interface name.
By doing so, the interface holding the default route (em0
) will
be chosen automatically.
Finally, skip
allows a given interface to be omitted from packet
processing.
The firewall will ignore traffic on the
lo(4) loopback interface.
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)The
match
rules used here accomplish two things:
normalizing incoming packets and performing network address translation,
with the egress
interface between the LAN and the public internet.
For a more detailed explanation of match
rules and their different
options, refer to the
pf.conf(5) manual.
antispoof quick for { egress $wired $wifi } block in quick on egress from <martians> to any block return out quick on egress from any to <martians>The antispoof keyword provides some protection from packets with spoofed source addresses. Incoming packets should be dropped if they appear to be from the list of unroutable addresses defined earlier. Such packets were likely sent due to misconfiguration, or possibly as part of a spoofing attack. Similarly, clients should not attempt to connect to such addresses. The "return" action is specified to prevent annoying timeouts for users. Note that this can cause problems if the router itself is also behind NAT.
block allThe firewall will set a "default deny" policy for all traffic, meaning that only incoming and outgoing connections which have been explicitly put in the ruleset will be allowed.
pass out quick inetAllow outgoing IPv4 traffic from both the gateway itself and the LAN clients.
pass in on { $wired $wifi } inetAllow internal LAN traffic.
pass in on egress inet proto tcp from any to (egress) port { 80 443 } rdr-to 192.168.1.2Forward incoming connections (on TCP ports 80 and 443, for a web server) to the machine at 192.168.1.2. This is merely an example of port forwarding.
# rcctl enable unbound # vi /var/unbound/etc/unbound.confSomething like this should work for most setups:
server: interface: 192.168.1.1 interface: 192.168.2.1 interface: 127.0.0.1 access-control: 192.168.1.0/24 allow access-control: 192.168.2.0/24 allow do-not-query-localhost: no hide-identity: yes hide-version: yes prefetch: yes forward-zone: name: "." forward-addr: X.X.X.X # IP of the preferred upstream resolverFurther configuration options can be found in the unbound.conf(5) manual. Outgoing DNS lookups can also be encrypted with the dnscrypt-proxy package or with unbound's built-in DNS over TLS support.
If the router should also use the caching resolver, its
/etc/resolv.conf
file should contain
nameserver 127.0.0.1
Once the changes are in place, reboot the system.