Aug 232011
 

Welcome to part seven of my multipart series on IPv6. In this post I’ll cover how to use packet filter (pf) on BSD to run a small network. The router is running FreeBSD 8.2, but this should apply equally well to either OpenBSD or FreeBSD with pf.

The biggest change for most people when configuring IPv6 is the lack of private addresses and associated network address translation. Almost every single residential or business workstation sits on a private IP address and uses NAT to connect through a public IP address to the rest of the Internet. NAT can cause a multitude of problems for users and protocols though so IPv6 was designed to obviate the need for NAT or private address space. However, many users (whether knowingly or not) depend on NAT for their internet security, and adapting to a world where everyone and everything has a direct public IP address is going to require some changes in perspective from network administrators, internet service providers, home users, and device manufacturers.

My network consists of a FreeBSD router and a mix of Linux, Windows, and Mac OS X hosts, plus assorted game systems, smartphones, wireless devices, etc. The WAN link is a DSL connection using a dual-stacked PPPoE connection, and I have LAN and DMZ networks. The DMZ uses a routed /29 for IPv4 connectivity, so the hosts in it have public addresses. For more details, please see part six of this series.

With my demand for bandwidth easily outstripping the supply, the implementation of traffic shaping techniques is important to how fast my Internet connection feels. I’ve used the ALTQ integration in packet filter to shape my traffic, and I’ve found it by far the best solution available, outperforming anything Linux or IPFW can do. I can do all of the following simultaneously: VoIP phone calls, online multiplayer gaming, YouTube videos, download files via Bit Torrent, upload large numbers of files via rsync, plus all the other services that are constantly connected to the internet (RSS feeds, IM clients, etc), all of it without degradation of the user experience.

It’s reasonable to assume that not all of the features of my home network will apply to your own circumstance (particularly the routed /29 subnet). Fortunately, you can just omit the sections pertaining to any superfluous features from my packet filter configuration below. I’ve also covered my (somewhat elaborate) configuration in this much earlier post. The general principals of my configuration are unchanged, though they differ in the details. If anything below leaves you confused, it might be worth reading the earlier post to better understand what I’m doing.

What follows is an annotated copy of my /etc/pf.conf:

[cc]
$ cat /etc/pf.conf
#################################################
# Macros #
#################################################
# WAN interface macros
wan_if = ng0

# Modem interface macros
modem1_if = em1
table const { $modem1_if:network }
modem2_if = em2
table const { $modem2_if:network }

# LAN interface macros
lan_if = em3
table const { 192.168.1.1/24 }
table const { 2001:0DB8:f00e:eb00::/64 }

# DMZ interface macros
dmz_if = em0
table const { 203.0.113.240/29 }
table const { 2001:0DB8:f00e:eb01::/64 }

# A couple quick helper macros
table const { fe80::/8 }
table const { ff02::/8 }

# Internal Host macros
table const { 192.168.1.25 }
table const { 2001:0DB8:f00e:eb00:216:3eff:fe7f:4ebe }
table const { 192.168.1.50 }
table const { 2001:0DB8:f00e:eb00:217:f2ff:fe02:a536 }
table const { 192.168.1.54 }
table const { 2001:0DB8:f00e:eb00:f2b4:79ff:fe1a:e59e }
table const { 192.168.1.71 }
table const { 192.168.1.80 }
table const { 203.0.113.242 }
table const { 2001:0DB8:f00e:eb01::242 }

# Port forward macros
mythbackend_tcp_defq = “{ 80 }”
mythbackend_tcp_blkq = “{ 51413, 51414 }”
mythbackend_udp_blkq = “{ 51413, 51414 }”
pap2t_udp_vipq = “{ 5060 }”

# ICMPv6 Types
icmpv6_types = “{ unreach, toobig, timex, paramprob, echoreq, echorep, neighbradv, neighbrsol, routeradv, routersol }”

# External Host macros
table const { \
192.168.1.71/32, \
192.168.1.72/32 }
table const { \
203.0.113.100/32, 203.0.113.158/32 }
table const { \
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.168.0.0/24, \
240.0.0.0/4, 255.255.255.255 }
table persist { 224.0.0.0/4, 239.0.0.0/4 }
[/cc]

The macro section includes all the macros that I’ll make extensive use of later on. My DSL modems are connected to em1 and em2, and have their own IPv4 subnets for connecting to the modem configuration interface, while em0 and em3 are the DMZ and LAN, respectively. I use tables to identify some of the important hosts on my network, and have macros for all the forwarded ports here. It makes it easy to add new port forwards. I also identify the VoIP gateways that I use, which is important for traffic shaping, which we’ll see a little further down in the file.

[cc]
#################################################
# Firewall Options #
#################################################
set skip on lo
set block-policy return
set state-policy if-bound
set loginterface $wan_if
set loginterface $dmz_if
set loginterface $lan_if
set limit states 30000
[/cc]

You don’t typically want to firewall any traffic on the loopback interface, so we set packet filter to skip it entirely. Setting the block-policy to return means that the firewall will send ICMP port unreachable responses to spurious connections, rather than simply dropping the packet. This is a matter of taste than anything else, and I like to reject the connections outright because it speeds up the rate of failure at the far end, since the connection doesn’t have to time out. All you lose is a little security through obscurity.

In addition, setting the state-policy to if-bound means that the state of a given connection is tied to the interface the state was created on. This is not the packet filter default, and it means that a connection from my LAN to an outside host will generate a pair of entries in the state table – one on the LAN interface and one on the WAN interface. This is required for the manner in which I do my traffic shaping, but it also means that the state table can get quite large. This isn’t an issue on a box with 512 megabytes of RAM, but would be a concern on a box with 16 megabytes of RAM. Relatedly, I set my state table to a size of 30k, which is triple the default.

[cc]
#################################################
# Scrub Options #
#################################################
# These scrub as per normal on the other interfaces
scrub in on $wan_if all random-id
scrub in on $lan_if all random-id
scrub in on $dmz_if all random-id
[/cc]

You’ll have to consult the packet filter FAQ or man page for a detailed description of what the scrub option does, but it’s useful to have.

[cc]
#################################################
# Queuing #
#################################################
# Set queues on wan_if
altq on $wan_if bandwidth 1200Kb hfsc (linkshare 1200Kb upperlimit 1200Kb) queue { wan_ackq, wan_dnsq, wan_vipq, wan_defq, wan_blkq }
queue wan_ackq bandwidth 15% priority 7 qlimit 30 hfsc (realtime 15%)
queue wan_dnsq bandwidth 5% priority 6 qlimit 30 hfsc (realtime 5%)
queue wan_vipq bandwidth 10% priority 5 qlimit 30 hfsc (realtime 90Kb)
queue wan_defq bandwidth 50% priority 4 qlimit 30 hfsc (realtime 40%)
queue wan_blkq bandwidth 5% priority 0 qlimit 10 hfsc (default ecn red upperlimit 500Kb)
[/cc]

This section is where some of the traffic shaping magic starts to happen. I define a Hierarchical Fair Service Curve (HFSC) queue tied to the WAN interface, which is how we’re going to control which types of traffic get priority over other types. This is a very simple HFSC setup that doesn’t use it fully, but I find it adequate for my needs at home. Essentially, I define a bunch of categories of traffic, and then rank them by their priority. You also define a maximum amount of bandwidth available to the queue. It should be noted that you want only reasonably queue traffic in one direction – upstream. You queue traffic that has not yet traversed your WAN connection, when you still have influence over the priority of the connections. There is no point in queuing traffic in the downstream direction, because once the packet is available to your to actually queue it has already traversed the WAN link which is the bottleneck. It’s pointless to queue downstream traffic. Further information can be found here and here.

[cc]
#################################################
# NAT Translations #
#################################################
# NAT traffic from the LAN to the tubes
nat on $wan_if from to any -> ($wan_if) static-port
nat on $dmz_if from to -> ($dmz_if)
nat on $modem1_if from to -> ($modem1_if)
nat on $modem2_if from to -> ($modem2_if)
nat-anchor “ftp-proxy/*”
# Forward ports as requested
rdr on $wan_if inet proto tcp from any to ($wan_if) port $macpro_tcp_blkq ->
rdr on $wan_if inet proto udp from any to ($wan_if) port $macpro_udp_blkq ->
rdr on $wan_if inet proto tcp from any to ($wan_if) port $mythbackend_tcp_defq ->
rdr on $wan_if inet proto tcp from any to ($wan_if) port $mythbackend_tcp_blkq ->
rdr on $wan_if inet proto udp from any to ($wan_if) port $mythbackend_udp_blkq ->
rdr on $wan_if inet proto udp from any to ($wan_if) port $pap2t_udp_vipq -> # UPnPd rdr anchor
rdr-anchor “miniupnpd”
# FTP proxy redirect and anchor
rdr pass on $lan_if inet proto tcp from to any port 21 -> 127.0.0.1 port 8021
rdr-anchor “ftp-proxy/*”
[/cc]

This section handles the NAT and redirect rules for packet filter. It’s irrelevant to IPv6, since neither NAT nor redirect rules are necessary in a world with only globally accessible addresses. Normally you don’t run your NAT with the static-port option, but I find it useful for online gaming.

[cc]
#################################################
# Filter Rules #
#################################################

################
# Block Rules #
################
# Block everything.
block log all
# Block logically impossible packets
block drop in log quick on $wan_if from to any
block drop out log on $wan_if from any to
# A little more pre-emptive removal
antispoof log for $wan_if
antispoof log for $lan_if
antispoof log for $dmz_if
[/cc]

Packet filter works on a last-match-wins paradigm, which is exactly the opposite of iptables in Linux. This means that packet filter rule sets start with the most general rules and get more specific as they go. Neither is better or worse, it’s just a matter of taste. In this instance, we start with a big block everything rule. This means this configuration is a default-deny rule set, and only traffic that is explicitly allowed by one of the following rules will be able to pass. The two rules pertaining to martians are the only rules in my rule set that use the quick option, which is a way to shortcut the usual last-match-wins logic. There should be no private network traffic on my WAN interface.

[cc]
###############################################
# Tag IPv4 Traffic To/From The Gateway Itself #
###############################################
# Allow inbound ICMP connections to the gateway
pass in log on $wan_if inet proto icmp from any to ($wan_if) queue wan_dnsq
pass in log on $lan_if inet proto icmp from any to ($lan_if) queue wan_dnsq
pass in log on $dmz_if inet proto icmp from any to ($dmz_if) queue wan_dnsq
# Allow inbound SSH connections to the gateway
pass in log on $wan_if inet proto tcp from any to ($wan_if) port ssh queue wan_defq
pass in log on $lan_if inet proto tcp from to ($lan_if) port ssh tag lan_gw
pass in log on $dmz_if inet proto tcp from to ($dmz_if) port ssh tag dmz_gw
# Allow outbound connections from the gateway
pass out log on $wan_if inet proto icmp from ($wan_if) to any queue wan_dnsq
pass out log on $wan_if inet proto { tcp, udp } from ($wan_if) to any queue wan_defq
pass out log on $wan_if inet proto udp from ($wan_if) to any port domain queue wan_dnsq
pass out log on $wan_if inet proto tcp from ($wan_if) to any port ssh queue wan_defq
# Allow gateway to connect to directly attached networks
pass out log on $modem1_if inet from ($modem1_if) to tag gw_modem1
pass out log on $modem2_if inet from ($modem2_if) to tag gw_modem2
pass out log on $lan_if inet from ($lan_if) to tag gw_lan
pass out log on $dmz_if inet from ($dmz_if) to tag gw_dmz
[/cc]

These rules apply to traffic dealing with the router itself. Mostly, it just allows inbound ICMP and SSH connections, while allowing all outbound connections (so I can do OS updates and keep my ports tree up to date, etc). In addition, the gateway has access to all the locally attached networks.

[cc]
###############################################
# Tag IPv6 Traffic To/From The Gateway Itself #
###############################################
# Allow inbound ICMP connections to the gateway
pass in log on $wan_if inet6 proto icmp6 all icmp6-type $icmpv6_types queue wan_dns1
pass in log on $wan_if inet6 proto icmp6 from any to ($wan_if) queue wan_dnsq
pass in log on $lan_if inet6 proto icmp6 from any to ($lan_if) queue wan_dnsq
pass in log on $dmz_if inet6 proto icmp6 from any to ($dmz_if) queue wan_dnsq
# Allow inbound SSH connections to the gateway
pass in log on $wan_if inet6 proto tcp from any to ($wan_if) port ssh queue wan_defq
pass in log on $lan_if inet6 proto tcp from any to ($lan_if) port ssh tag lan_gw
pass in log on $dmz_if inet6 proto tcp from any to ($dmz_if) port ssh tag dmz_gw
# Allow outbound connections from the lan interface
pass out log on $wan_if inet6 proto icmp6 all icmp6-type $icmpv6_types queue wan_dnsq
pass out log on $wan_if inet6 proto icmp6 from ($wan_if) to any queue wan_dnsq
pass out log on $wan_if inet6 proto tcp from ($wan_if) to any queue (wan_defq, wan_ackq)
pass out log on $wan_if inet6 proto udp from ($wan_if) to any queue wan_defq
pass out log on $wan_if inet6 proto udp from ($wan_if) to any port domain queue wan_dnsq
# Allow gateway to connect to directly attached networks
pass out log on $lan_if inet6 proto icmp6 all icmp6-type $icmpv6_types tag gw_lan
pass out log on $dmz_if inet6 proto icmp6 all icmp6-type $icmpv6_types tag gw_dmz
pass out log on $lan_if inet6 from to tag gw_lan
pass out log on $dmz_if inet6 from to tag gw_dmz
pass out log on $lan_if inet6 from to tag gw_lan
pass out log on $dmz_if inet6 from to tag gw_dmz
pass out log on $lan_if inet6 from ($lan_if) to tag gw_lan
pass out log on $dmz_if inet6 from ($dmz_if) to tag gw_dmz
[/cc]

As you can see, the IPv6 rule set is basically just a copy of the IPv4 rule set, with a bit of extra care taken for ICMPv6 and link-local connections. This is the same pattern we saw in the post on Host Security with FreeBSD, and we’ll see this pattern repeated throughout the rest of this rule set as well.

[cc]
####################################
# Tag IPv4 Traffic To/From The DMZ #
####################################
# Allow access to the DMZ
pass in log on $wan_if inet proto icmp from any to tag wan_dmz queue wan_dnsq
pass in log on $wan_if inet proto tcp from any to tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet proto udp from any to tag wan_dmz queue wan_defq
pass in log on $wan_if inet proto tcp from any to port ftp tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet proto tcp from any to port ssh tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet proto tcp from any to port domain tag wan_dmz queue (wan_dnsq, wan_ackq)
pass in log on $wan_if inet proto udp from any to port domain tag wan_dmz queue wan_dnsq
pass in log on $wan_if inet proto tcp from any to port http tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet proto tcp from any to port 5900:5909 tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet proto tcp from any to port 42991 tag wan_dmz queue (wan_defq, wan_ackq)
# Allow access from the DMZ
pass in log on $dmz_if inet proto icmp from to any tag wan_dns
pass in log on $dmz_if inet proto tcp from to any tag wan_def
pass in log on $dmz_if inet proto udp from to any tag wan_def
pass in log on $dmz_if inet proto tcp from to any port ftp tag wan_def
pass in log on $dmz_if inet proto tcp from to any port ssh tag wan_def
pass in log on $dmz_if inet proto tcp from to any port domain tag wan_dns
pass in log on $dmz_if inet proto udp from to any port domain tag wan_dns
pass in log on $dmz_if inet proto tcp from to any port http tag wan_def
pass in log on $dmz_if inet proto tcp from to any port ntp tag wan_dns
pass in log on $dmz_if inet proto udp from to any port ntp tag wan_dns
pass in log on $dmz_if inet from to ($dmz_if) tag dmz_gw
[/cc]

This set of rules applies to traffic for the routed /29 subnet. I don’t do any actual firewalling of traffic here, because my intention for this subnet is that it is as open as possible (I depend on host security for hosts in this subnet). That is why the first rules in either direction allow all ICMP, TCP, and UDP traffic respectively. All of the above rules only dictate which category the various types of traffic will end up in.

[cc]
####################################
# Tag IPv6 Traffic To/From The DMZ #
####################################
# Allow access to the DMZ
pass in log on $wan_if inet6 proto icmp6 from any to tag wan_dmz queue wan_dnsq
pass in log on $wan_if inet6 proto tcp from any to tag wan_dmz queue (wan_defq, wan_ackq)
pass in log on $wan_if inet6 proto udp from any to tag wan_dmz queue wan_defq
# Allow access from the DMZ
pass in log on $dmz_if inet6 proto icmp6 all icmp6-type $icmpv6_types tag dmz_gw
pass in log on $dmz_if inet6 proto icmp6 from to any tag wan_dns
pass in log on $dmz_if inet6 proto tcp from to any tag wan_def
pass in log on $dmz_if inet6 proto udp from to any tag wan_def
pass in log on $dmz_if inet6 from to tag dmz_gw
pass in log on $dmz_if inet6 from to tag dmz_gw
pass in log on $dmz_if inet6 from to tag dmz_lan
pass in log on $dmz_if inet6 from to ($dmz_if) tag dmz_gw
[/cc]

Again, this is mostly just a recreation of the IPv4 rules for IPv6. I have fewer rules for separating out the traffic into different categories, but that is entirely due to laziness on my part. I haven’t yet done much extensive testing of IPv6 in the DMZ, so I haven’t had a need to categorize the traffic yet.

[cc]
####################################
# Tag IPv4 Traffic To/From The LAN #
####################################
# Allow traffic from the tubes to the LAN
pass in log on $wan_if inet proto tcp from any to port $mythbackend_tcp_defq tag wan_lan queue wan_defq
pass in log on $wan_if inet proto tcp from any to port $mythbackend_tcp_blkq tag wan_lan queue wan_blkq
pass in log on $wan_if inet proto udp from any to port $mythbackend_udp_blkq tag wan_lan queue wan_blkq
pass in log on $wan_if inet proto udp from any to port $pap2t_udp_vipq tag wan_lan queue wan_vipq
# Allow traffic from the LAN to the tubes
pass in log on $lan_if inet proto icmp from to any tag wan_dns
pass in log on $lan_if inet proto gre from to any tag wan_def
pass in log on $lan_if inet proto tcp from to any tag wan_blk
pass in log on $lan_if inet proto udp from to any tag wan_blk
pass in log on $lan_if inet proto tcp from to any tag wan_def # Easier than figuring out which
pass in log on $lan_if inet proto udp from to any tag wan_def # ports belong to which game
pass in log on $lan_if inet proto tcp from to any tag wan_def # Easier than figuring out which
pass in log on $lan_if inet proto udp from to any tag wan_def # ports need to be pulled out
pass in log on $lan_if inet proto tcp from to any tag wan_def # Easier than figuring out which
pass in log on $lan_if inet proto udp from to any tag wan_def # ports belong to which game
pass in log on $lan_if inet proto tcp from to any port domain tag wan_dns
pass in log on $lan_if inet proto udp from to any port domain tag wan_dns
pass in log on $lan_if inet proto tcp from to any port ntp tag wan_dns
pass in log on $lan_if inet proto udp from to any port ntp tag wan_dns
pass in log on $lan_if inet proto tcp from to any port ssh tag wan_def
pass in log on $lan_if inet proto tcp from to any port smtp tag wan_def
pass in log on $lan_if inet proto tcp from to any port http tag wan_def
pass in log on $lan_if inet proto tcp from to any port https tag wan_def
pass in log on $lan_if inet proto tcp from to any port pop3 tag wan_def
pass in log on $lan_if inet proto tcp from to any port imap tag wan_def
pass in log on $lan_if inet proto tcp from to any port smtps tag wan_def
pass in log on $lan_if inet proto tcp from to any port submission tag wan_def
pass in log on $lan_if inet proto tcp from to any port imaps tag wan_def
pass in log on $lan_if inet proto tcp from to any port pop3s tag wan_def
pass in log on $lan_if inet proto tcp from to any port pptp tag wan_def
pass in log on $lan_if inet proto tcp from to any port isakmp tag wan_def
pass in log on $lan_if inet proto tcp from to any port 1863 tag wan_def # MSN
pass in log on $lan_if inet proto tcp from to any port rdp tag wan_def
pass in log on $lan_if inet proto tcp from to any port aol tag wan_def
pass in log on $lan_if inet proto tcp from to any port xmpp-client tag wan_def
pass in log on $lan_if inet proto tcp from to any port 3784 tag wan_vip # Ventrilo
pass in log on $lan_if inet proto udp from to any port 3784 tag wan_vip # Ventrilo
pass in log on $lan_if inet proto udp from to any port 4380 tag wan_def # Steam Client
pass in log on $lan_if inet proto udp from to any port 5060 tag wan_vip # SIP/iChat
pass in log on $lan_if inet proto tcp from to any port 5190 tag wan_def # iChat
pass in log on $lan_if inet proto udp from to any port 5190 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 5220 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 5222 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 5223 tag wan_def # iChat
pass in log on $lan_if inet proto udp from to any port 5297 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 5298 tag wan_def # iChat
pass in log on $lan_if inet proto udp from to any port 5298 tag wan_def # iChat
pass in log on $lan_if inet proto udp from to any port 5353 tag wan_def # iChat
pass in log on $lan_if inet proto udp from to any port 5678 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 6665:6669 tag wan_def # IRC
pass in log on $lan_if inet proto tcp from to any port 8000 tag wan_def # Internet Radio
pass in log on $lan_if inet proto tcp from to any port 8001 tag wan_def # Internet Radio
pass in log on $lan_if inet proto udp from to any port 8080 tag wan_def # Alternate HTTP
pass in log on $lan_if inet proto tcp from to any port 9418 tag wan_def # Git
pass in log on $lan_if inet proto udp from to any port 9418 tag wan_def # Git
pass in log on $lan_if inet proto udp from to any port 16384:16403 tag wan_def # iChat
pass in log on $lan_if inet proto tcp from to any port 25565 tag wan_def # Minecraft
pass in log on $lan_if inet proto udp from to any port 27000:27030 tag wan_def # Steam Client
pass in log on $lan_if inet proto udp from to tag wan_vip # Any traffic to HIP SBCs
pass in log on $lan_if inet proto tcp from to any tag wan_vip # VoIP
pass in log on $lan_if inet proto udp from to any tag wan_vip # VoIP
# UPnPd rule and anchor
pass in log on $lan_if from any to tag wan_def
anchor “miniupnpd”
# FTP proxy anchor
anchor “ftp-proxy/*”
# Allow traffic from the LAN to the router and the DMZ
pass in log on $lan_if inet from to tag lan_nex1
pass in log on $lan_if inet from to tag lan_nex2
pass in log on $lan_if inet from to tag lan_dmz
pass in log on $lan_if inet from to ($lan_if) tag lan_gw
[/cc]

The first section deals with traffic from the Internet destined to the LAN, and is really just the pass rules for the port forwards I’ve done. All other inbound connections are blocked.

The second section deals with outbound traffic. The basic idea is I first classify everything as bulk traffic, which gets the worst priority. Then I selectively identify different traffic that I want to be classified as something other than bulk data. I could have re-written all of those rules into just one rule, using a macro containing all the ports I wanted to treat as something other than bulk, but I find this easier to read and debug, even if it does take a bit to scroll through it. Also, note that I use the destination of to identify traffic destined to my VoIP providers.

[cc]
####################################
# Tag IPv6 Traffic To/From The LAN #
####################################
# Allow traffic from the tubes to the LAN
pass in log on $wan_if inet6 proto tcp from any to port $macpro_tcp_blkq tag wan_lan queue wan_blkq
pass in log on $wan_if inet6 proto udp from any to port $macpro_udp_blkq tag wan_lan queue wan_blkq
pass in log on $wan_if inet6 proto tcp from any to port $mythbackend_tcp_defq tag wan_lan queue wan_defq
pass in log on $wan_if inet6 proto tcp from any to port $mythbackend_tcp_blkq tag wan_lan queue wan_blkq
pass in log on $wan_if inet6 proto udp from any to port $mythbackend_udp_blkq tag wan_lan queue wan_blkq
# Allow traffic from the LAN to the tubes
pass in log on $lan_if inet6 proto icmp6 all icmp6-type $icmpv6_types tag lan_gw
pass in log on $lan_if inet6 proto icmp6 from to any tag wan_dns
pass in log on $lan_if inet6 proto gre from to any tag wan_def
pass in log on $lan_if inet6 proto tcp from to any tag wan_blk
pass in log on $lan_if inet6 proto udp from to any tag wan_blk
pass in log on $lan_if inet6 proto tcp from to any tag wan_def # Easier than figuring out which
pass in log on $lan_if inet6 proto udp from to any tag wan_def # ports belong to which game
pass in log on $lan_if inet6 proto tcp from to any tag wan_def # Easier than figuring out which
pass in log on $lan_if inet6 proto udp from to any tag wan_def # ports need to be pulled out
pass in log on $lan_if inet6 proto tcp from to any port domain tag wan_dns
pass in log on $lan_if inet6 proto udp from to any port domain tag wan_dns
pass in log on $lan_if inet6 proto tcp from to any port ntp tag wan_dns
pass in log on $lan_if inet6 proto udp from to any port ntp tag wan_dns
pass in log on $lan_if inet6 proto tcp from to any port ssh tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port smtp tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port http tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port https tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port pop3 tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port imap tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port smtps tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port submission tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port imaps tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port pop3s tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port pptp tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port isakmp tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port 1863 tag wan_def # MSN
pass in log on $lan_if inet6 proto tcp from to any port rdp tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port aol tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port xmpp-client tag wan_def
pass in log on $lan_if inet6 proto tcp from to any port 3784 tag wan_vip # Ventrilo
pass in log on $lan_if inet6 proto udp from to any port 3784 tag wan_vip # Ventrilo
pass in log on $lan_if inet6 proto udp from to any port 4380 tag wan_def # Steam Client
pass in log on $lan_if inet6 proto udp from to any port 5060 tag wan_vip # SIP/iChat
pass in log on $lan_if inet6 proto tcp from to any port 5190 tag wan_def # iChat
pass in log on $lan_if inet6 proto udp from to any port 5190 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 5220 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 5222 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 5223 tag wan_def # iChat
pass in log on $lan_if inet6 proto udp from to any port 5297 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 5298 tag wan_def # iChat
pass in log on $lan_if inet6 proto udp from to any port 5298 tag wan_def # iChat
pass in log on $lan_if inet6 proto udp from to any port 5353 tag wan_def # iChat
pass in log on $lan_if inet6 proto udp from to any port 5678 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 6665:6669 tag wan_def # IRC
pass in log on $lan_if inet6 proto tcp from to any port 8000 tag wan_def # Internet Radio
pass in log on $lan_if inet6 proto tcp from to any port 8001 tag wan_def # Internet Radio
pass in log on $lan_if inet6 proto udp from to any port 8080 tag wan_def # Alternate HTTP
pass in log on $lan_if inet6 proto tcp from to any port 9418 tag wan_def # Git
pass in log on $lan_if inet6 proto udp from to any port 9418 tag wan_def # Git
pass in log on $lan_if inet6 proto udp from to any port 16384:16403 tag wan_def # iChat
pass in log on $lan_if inet6 proto tcp from to any port 25565 tag wan_def # Minecraft
pass in log on $lan_if inet6 proto udp from to any port 27000:27030 tag wan_def # Steam Client
# Allow traffic from the LAN to the router and the DMZ
pass in log on $lan_if inet6 from to tag gw_lan
pass in log on $lan_if inet6 from to tag lan_gw
pass in log on $lan_if inet6 from to tag lan_dmz
pass in log on $lan_if inet6 from to ($lan_if) tag lan_gw
[/cc]

Here’s where the real difference between IPv4 with NAT and IPv6 with global addresses appears, within the context of home networking. Whereas the first rules for the DMZ allow traffic from the Internet to access the DMZ subnet unhindered, there are no such rules for the LAN. The only rules that allow inbound traffic are in fact recreations of the port forwards from IPv4 – only in this case it’s not a port forward since there is no NAT to contend with. Because of the ‘block log all’ rule that started the entire rule set, any inbound IPv6 connections to any hosts in my LAN will still be blocked by the firewall unless it matches one of the connections I’ve expressly allowed. That’s all there is that separates IPv4 from IPv6 in a home network sense – instead of relying on NAT to provide an implicit inbound block rule you need an explicit inbound block rule.

The rest of the rules are just a duplicate of the IPv4 rules again. There’s no need for an FTP proxy, and more care taken for ICMPv6 and link-local addresses

[cc]
######################
# Policy Enforcement #
######################
# Allow traffic from the gateway to other networks
pass out log on $nex1_if tagged gw_nex1
pass out log on $nex2_if tagged gw_nex2
pass out log on $lan_if tagged gw_lan
pass out log on $dmz_if tagged gw_dmz
# Allow traffic from the local networks to other networks
pass out log on $nex1_if tagged lan_nex1
pass out log on $nex2_if tagged lan_nex2
pass out log on $dmz_if tagged wan_dmz
pass out log on $dmz_if tagged lan_dmz
pass out log on $lan_if tagged wan_lan
pass out log on $lan_if tagged dmz_lan
# Allow multicast traffic
pass out log on $lan_if from any to tag lan

# Allow traffic out the WAN interface
pass out log on $wan_if proto icmp6 tagged wan_dns queue wan_dnsq
pass out log on $wan_if proto icmp tagged wan_dns queue wan_dnsq
pass out log on $wan_if proto gre tagged wan_def queue wan_defq
pass out log on $wan_if proto tcp tagged wan_dns queue (wan_dnsq, wan_ackq)
pass out log on $wan_if proto udp tagged wan_dns queue wan_dnsq
pass out log on $wan_if proto tcp tagged wan_vip queue (wan_vip, wan_ackq)
pass out log on $wan_if proto udp tagged wan_vip queue wan_vipq
pass out log on $wan_if proto tcp tagged wan_def queue (wan_defq, wan_ackq)
pass out log on $wan_if proto udp tagged wan_def queue wan_defq
pass out log on $wan_if proto tcp tagged wan_blk queue (wan_blkq, wan_ackq)
pass out log on $wan_if proto udp tagged wan_blk queue wan_blkq
[/cc]

Up until this point in the rules, we’ve been dealing exclusively with ‘pass in’ rules, allowing traffic into the firewall. In each of those rules, we tagged the packets according to what type of traffic it was. In the final section, we put all of our ‘pass out’ rules, which dictate how traffic can leave the firewall. This type of configuration is called a policy-based firewall. We have a large and specific set of rules that separates different connections into different categories, and then we have a final set of rules that don’t attempt to categorize or identify connections, it just determines what each category of traffic is allowed to do.

Traffic to and from locally attached networks (the DMZ, the LAN, and the two modems) is unhindered by any traffic shaping. These connections all happen over gigabit switching (either physical or virtual, in the case of virtual machines), so there’s little point in traffic shaping this traffic. Connections that go out the WAN though are subject to the ALTQ we defined at the top of the file.

Once you’ve implemented something like this, if you find some types of traffic are sluggish or unresponsive, you will want to tweak the ALTQ itself – assuming you have actually got your traffic properly categorized. If you’re unsure if you’ve got your traffic properly identified I’ve always found the tool pftop to be invaluable in determining how traffic is flowing through your firewall. Also useful is this (bash) alias:

[cc]
$ cat .bash_aliases | grep pfdump
alias pfdump=’tcpdump -n -e -ttt -i pflog0 ‘
[/cc]

If you’re trying to use tcpdump (and the alias above uses tcpdump) then you’ll want to install the version from ports (at least with FreeBSD-8.2-RELEASE) as it has better capabilityies with identifying IPv6 traffic. The version of tcpdump can identify that packet is an IPv6 packet, but is unable to tell anything more about it (not even the source or destination port, for example).

Sorry, the comment form is closed at this time.