Hi all,
I've been playing with pf for a number of months now and I've come across a
situation that I'm having trouble finding a solution for. Specifically I'm
working with the following topology:
Internet --- OpenBSD box --- Cisco router --- other devices
The Cisco router (a small 800 series router) is sitting behind an OpenBSD box
(version 5.1). This Cisco router has an IPsec tunnel connected to another
router out on the Internet. So, all the OpenBSD box sees is a bunch of
encrypted frames (udp port 4500). That's all fine and dandy, that works well,
no problems there.
However, some of the devices behind the Cisco router are setting the tos/dscp
bits on their packets. I would like to be able to prioritize those packets in
pf for altq handling. So, I've created the following rules:
local_nets = "{ 172.28.1.0/24, 172.28.10.0/24, 172.28.11.0/24 }"
work871 = "172.28.1.3"
pass in quick inet proto udp from $work871 tos 0xB8 tag VOIP-RTP
pass in quick inet proto udp from $work871 tos 0x60 tag VOIP-SIG
pass in quick inet proto { tcp, udp } from $local_nets
The idea here being that ingress traffic from 172.28.1.3, with the various tos
values will be tagged with a specific tag. On the egress side I match on that
tag and then apply it to a queue. That isn't working though. It seems that PF
creates a state entry first for the overall ipsec tunnel using the third rule.
After that state gets established all subsequent packets do not evaluate the
rules, even if those packets have different tos values. This leaves me to
believe that pf isn't creating a state entry tuple that contains the tos value.
I've confirmed the TOS bits are being carried through to the IP header of the
IPSEC packets. Here's a tcpdump of the incoming packets from my LAN interface
(vr0):
tcpdump: listening on vr0, link-type EN10MB (Ethernet), capture size 65535 bytes
21:37:39.464357 IP (tos 0xc0, ttl 255, id 848, offset 0, flags [none], proto
UDP (17), length 144)
172.28.1.3.4500 > 1.1.1.1.4500: UDP-encap: ESP(spi=0x32284280,seq=0x12e),
length 116
21:37:39.483350 IP (tos 0xc0, ttl 255, id 1707, offset 0, flags [none], proto
UDP (17), length 29)
172.28.1.3.4500 > 64.102.7.50.4500: isakmp-nat-keep-alive
21:37:42.365389 IP (tos 0x0, ttl 255, id 849, offset 0, flags [none], proto UDP
(17), length 152)
172.28.1.3.4500 > 1.1.1.1.4500: UDP-encap: ESP(spi=0x32284280,seq=0x12f),
length 124
21:37:45.465724 IP (tos 0xc0, ttl 255, id 850, offset 0, flags [none], proto
UDP (17), length 144)
172.28.1.3.4500 > 1.1.1.1.4500: UDP-encap: ESP(spi=0x32284280,seq=0x130),
length 116
21:37:47.370081 IP (tos 0x0, ttl 255, id 851, offset 0, flags [none], proto UDP
(17), length 152)
172.28.1.3.4500 > 1.1.1.1.4500: UDP-encap: ESP(spi=0x32284280,seq=0x131),
length 124
21:37:49.256302 IP (tos 0x60, ttl 255, id 852, offset 0, flags [none], proto
UDP (17), length 120)
172.28.1.3.4500 > 1.1.1.1.4500: UDP-encap: ESP(spi=0x32284280,seq=0x132),
length 92
>From this it's clear that the last packet has "tos 0x60" set. However, if I
>look at this particular rule, it doesn't have any matches or state entries:
pass in quick inet proto udp from 172.28.1.3 to any tos 0x60 keep state tag
VOIP-SIG
[ Evaluations: 34 Packets: 0 Bytes: 0 States: 0 ]
[ Inserted: uid 0 pid 13666 State Creations: 0 ]
Instead, there's a state entry logged for this traffic under the third rule:
all udp 1.1.1.1:4500 <- 172.28.1.3:4500 MULTIPLE:MULTIPLE
age 00:15:50, expires in 00:00:57, 394:196 pkts, 52356:39176 bytes, rule 37
Based on the above, it seems like the state entries don't include the tos
information making it impossible to properly classify traffic that is encrypted
with ipsec. The only way to differentiate various traffic streams contained
within the tunnel is via tos/dscp. This is fairly common practice in the
Enterprise routing space. I'd love to be able to do the same thing here.
Am I missing something obvious? I've tested OpenBSD 5.1 and (for what its
worth) FreeBSD 9.0 and also pfsense 2.1beta1, I see the same behavior on all of
them.
Thanks in advance,
Adam