My OpenBSD firewall: pf + single ISP + multiple dynamic IPs – v3

Upgrading my firewall to OpenBSD 5.3 required updating my “multihoming-with-single-ISP” patch (see previous and original posts), as dhclient-script is no longer used. Instead, there is a new file, kroute.c. Luckily, moving the functionality from the shell script into C code was quite straightforward.

Here is the current patch to /usr/src/sbin/dhclient:

--- dhclient.c.orig	2013-08-02 10:17:29.000000000 +0300
+++ dhclient.c	2013-08-02 10:17:29.000000000 +0300
@@ -858,7 +858,10 @@
 	client->xid = arc4random();
 	make_request(client->active);
 
-	if (client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
+	/*if (client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {*/
+	if (0 && client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
 		memcpy(&client->destination.s_addr,
 		    client->active->options[DHO_DHCP_SERVER_IDENTIFIER].data,
 		    client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len);
--- kroute.c.orig	2013-08-02 10:17:29.000000000 +0300
+++ kroute.c	2013-08-02 20:20:42.000000000 +0300
@@ -256,6 +256,9 @@
 	struct sockaddr_rtlabel label;
 	struct iovec iov[5];
 	int s, len, i, iovcnt = 0;
+	char buf[256];
 
 	/*
 	 * Add a default route via the specified address.
@@ -339,6 +342,17 @@
 	iov[iovcnt].iov_base = &label;
 	iov[iovcnt++].iov_len = sizeof(label);
 
+	/* Update next hop to pf route-to rules */
+	snprintf(buf, 256, "/sbin/pfctl -t gw_%s -T flush", ifi->name);
+	if (system(buf))
+		warning("failed to flush pf table: %s", strerror(errno));
+	snprintf(buf, 256, "/sbin/pfctl -t gw_%s -T add %s", ifi->name,
+		inet_ntoa(gateway.sin_addr));
+	if (system(buf))
+		warning("failed to add to pf table: %s", strerror(errno));
+
 	/* Check for EEXIST since other dhclient may not be done. */
 	for (i = 0; i < 5; i++) {
 		if (writev(s, iov, iovcnt) != -1)

Here is the patch to /etc/rc:

--- rc.orig	2013-08-02 10:17:29.000000000 +0300
+++ rc	2013-08-02 10:17:29.000000000 +0300
@@ -357,6 +357,14 @@
 	mv -f /etc/resolv.conf.save /etc/resolv.conf
 	touch /etc/resolv.conf
 fi
+
+# Allow em0 to receive vlan packets with different MAC addresses
+ifconfig em0 up
+ifconfig bridge0 create
+brconfig bridge0 add em0
+
 . /etc/netstart
 echo rekey > /dev/arandom	# any write triggers an RC4 rekey
 
@@ -370,6 +378,16 @@
 	fi
 fi
 
+# Initialise next hops for pf's route-to rules
+pfctl -t gw_vlan201 -T add \
+    `netstat -f inet -rn | grep default | grep vlan201 | awk '{print $2}'`
+pfctl -t gw_vlan202 -T add \
+    `netstat -f inet -T1 -rn | grep default | grep vlan202 | awk '{print $2}'`
+pfctl -t gw_vlan203 -T add \
+    `netstat -f inet -T2 -rn | grep default | grep vlan203 | awk '{print $2}'`
+
 mount -s /usr >/dev/null 2>&1
 mount -s /var >/dev/null 2>&1

And finally, this is a working /etc/pf.conf:

###############################################################################
# Macros
###############################################################################

if_int      = "re0"
if_ext1     = "vlan201"
if_ext2     = "vlan202"
if_ext3     = "vlan203"
if_extv6    = "gif0"
all_ifs     = "{" $if_int $if_ext1 $if_ext2 $if_ext3 $if_extv6 "}"
ext_ifs     = "{" $if_ext1 $if_ext2 $if_ext3 $if_extv6 "}"
ext_ifs_v4  = "{" $if_ext1 $if_ext2 $if_ext3 "}"
ext_ifs_v6  = "{" $if_extv6 "}"

if_int_v4   = "10.0.0.xx"
home_net_v4 = "10.0.0.0/24"
if_int_v6ll = "fe80::xxx"
if_int_v6   = "2001:xxx"
if_ext_v6   = "2001:xxx"
home_net_v6 = "2001:xxx::/64"

core7       = "10.0.0.xx"
ps3         = "10.0.0.xx"

###############################################################################
# Tables
###############################################################################

table  persist {}
table  persist {}
table  persist {}

table  const persist {   \
    127.0.0.0/8                        \
    10.0.0.0/8                         \
    172.16.0.0/12                      \
    192.168.0.0/16                     \
}

table  const persist {         \
    x.x.x.x                            \
}

table  const persist {        \
    x.x.x.x                            \
}

###############################################################################
# Options
###############################################################################

set skip on lo0
set block-policy return
set loginterface $if_ext1
set state-policy if-bound

###############################################################################
# Packet normalisation
###############################################################################

match on $if_ext1 all scrub (random-id reassemble tcp)
match on $if_ext2 all scrub (random-id reassemble tcp)
match on $if_ext3 all scrub (random-id)

## NOTE: "reassemble tcp" breaks PS3 downloads and may break something else too

###############################################################################
# Translation/redirection rules
###############################################################################

# FTP proxy states need to override the rules below
anchor "ftp-proxy/*"

# NAT
match out on $if_ext3 inet from $ps3 to any nat-to $if_ext3 static-port
match in  on $if_ext3 inet from any to $if_ext3 rdr-to $ps3 rtable 0

match out on $if_ext2 inet from $core7 to any nat-to $if_ext2 static-port
match in  on $if_ext2 inet from any to $if_ext2 rdr-to $core7 rtable 0

match out on $if_ext1 from $home_net_v4 nat-to ($if_ext1)

###############################################################################
# Filter rules
###############################################################################

##
## GENERAL
##

# Block and log everything by default
block log all

# Antispoofing on all interfaces
antispoof quick for $all_ifs

# Block private addresses on external interfaces
block drop in  quick on $ext_ifs from 
block drop out quick on $ext_ifs to   

# Block IPv6 on external IPv4 interfaces
block drop quick on $ext_ifs_v4 inet6 all

# Block IPv4 on external IPv6 interfaces
block drop quick on $ext_ifs_v6 inet all

##
## INCOMING
##

##########
# if_int #
##########

# FTP proxy
pass in quick on $if_int inet proto tcp from $home_net_v4 to port ftp \
    divert-to 127.0.0.1 port 8021

# ps3
pass in quick on $if_int from $ps3 to $if_int_v4
pass in quick on $if_int from $ps3 route-to ($if_ext3 )

# core7
pass in quick on $if_int from $core7 to $if_int_v4
pass in quick on $if_int from $core7 route-to ($if_ext2 )

# Other home network nodes
pass in quick on $if_int from $home_net_v4 to $if_int_v4
pass in quick on $if_int from $home_net_v4 route-to ($if_ext1 )

# IPv6
pass in quick on $if_int from fe80::/16 to $if_int_v6ll
pass in quick on $if_int from fe80::/16 to ff02::/16
pass in quick on $if_int from $home_net_v6

###########
# if_ext1 #
###########

# IPv6 tunneling
pass in quick on $if_ext1 proto icmp from a.b.c.d to ($if_ext1)
pass in quick on $if_ext1 proto ipv6 from x.y.z.w to ($if_ext1)

# Pass in SSH from addresses listed in ssh_ok table
pass in quick on $if_ext1 proto tcp from  to ($if_ext1) port ssh
 
# Pass in HTTP from addresses listed in http_ok table
pass in quick on $if_ext1 proto tcp from  to ($if_ext1) port http
 
###################
# if_ext2 (core7) #
###################

# Steam (https://support.steampowered.com/kb_article.php?ref=8571-GLVN-8711)
pass in quick on $if_ext2 proto tcp to $core7 port 27014:27050
pass in quick on $if_ext2 proto udp to $core7 port 4380
pass in quick on $if_ext2 proto udp to $core7 port 27000:27030

# Black Ops 2
pass in quick on $if_ext2 proto tcp to $core7 port 3074
pass in quick on $if_ext2 proto udp to $core7 port 3074

#################
# if_ext3 (ps3) #
#################

# Nothing

##
## OUTGOING
##

##########
# if_int #
##########

# IPv4 from Internet to home network
pass out quick on $if_int to $ps3 received-on $if_ext3 \
    reply-to ($if_ext3 )
pass out quick on $if_int to $core7 received-on $if_ext2 \
    reply-to ($if_ext2 )
pass out quick on $if_int to $home_net_v4 received-on $if_ext1 \
    reply-to ($if_ext1 )

# IPv4 from fw to home network
pass out quick on $if_int from $if_int_v4 to $home_net_v4

# IPv6 from fw to home network
pass out quick on $if_int from $if_int_v6ll to fe80::/16
pass out quick on $if_int from $if_int_v6ll to ff02::/16
pass out quick on $if_int from $if_int_v6   to $home_net_v6
pass out quick on $if_int from $if_int_v6   to ff02::/16

###########
# if_ext1 #
###########

# IPv6 tunneling
pass out quick on $if_ext1 proto icmp from ($if_ext1) to a.b.c.d
pass out quick on $if_ext1 proto ipv6 from ($if_ext1) to x.y.z.w

# The rest
pass out quick on $if_ext1 inet from ($if_ext1) modulate state

###################
# if_ext2 (core7) #
###################

pass out quick on $if_ext2 inet from ($if_ext2) modulate state rtable 1

#################
# if_ext3 (ps3) #
#################

pass out quick on $if_ext3 inet from ($if_ext3) modulate state rtable 2

############
# if_extv6 #
############

pass out quick on $if_extv6 inet6 from $if_int_v6ll modulate state
pass out quick on $if_extv6 inet6 from $if_ext_v6 modulate state
pass out quick on $if_extv6 inet6 from $home_net_v6 modulate state
Facebooktwittergoogle_plusredditpinterestlinkedinmail