Thursday, January 5, 2012

VoIP Voice Over IP on PF Packet Filter firewall

# vim /etc/pf.conf
wan_if0 = "re0"
voip_phone_ip = ""
voip_ports = "{5059 5060 5061}"

# Return error codes for ports that are blocked. Allows faster error recovery
set block-policy return

### enable queueing on the external interface. Separate voice traffic and data first, then
### classify the data.
altq on $wan_if0 hfsc bandwidth 512Kb queue { q_voice, q_other }
queue q_voice bandwidth 3.84Kb priority 6 hfsc(realtime 96Kb)
queue q_other bandwidth 416Kb hfsc { q_pri, q_std, q_low }
queue q_pri bandwidth 200Kb priority 3 hfsc(red realtime 64Kb)
queue q_std bandwidth 200Kb priority 2 hfsc(default red )
queue q_low bandwidth 3.84Kb priority 1 hfsc(red )

### [NAT_VOIP] Voice Over IP Phone
### One translation line per IP phone. static-port is necessary to make pf retain the UDP
### ephemeral port, so that the remote SIP proxy knows what session we belong to
nat on $wan_if0 proto udp from $cn_voip_phone_ip to any -> ($wan_if0) static-port

### [NAT] Generic NAT rule for all internal network devices
nat on $wan_if0 from $lan_if/24 to any -> $wan_if0

### [VOIP] Voice Over IP - Allow external SIP control traffic
pass in quick log on $lan_if proto udp from $cn_voip_phone_ip to any tag VOIP keep state
pass out quick log on $wan_if0 proto {tcp udp} from $wan_if0 to any port $voip_ports keep state

pass out quick log on $wan_if0 tagged VOIP queue q_voice keep state

Troubleshooting and verification

To verify that the implementation works as expected, a media stream should be setup from the internal network, NATted and forwarded to the external SIP gateway. Source and destination ports for control traffic (destination port 5060) and media traffic (varies) should remain unchanged by the gateway. Finally, your phones should work :)
To verify correct packet prioritization, saturate the uplink with a large upload and attempt to use the IP phone at the same time. The IP phone traffic should get mapped to the high priority queue and voice quality should be good at the remote end. Because of ample download bandwidth, queueing is usually not needed and FreeBSD regular packet forwarding is sufficient.

Check status of queues:
# pfctl -vsq -v

Flush state table:
# pfctl -F state (Needed when updating ruleset since queue tagging persists with state entries)

Check firewall rule hit count:
# pfctl -s rules -v


No comments: