Squid, WCCPv2 and IPFW Tables under FreeBSD

Last Modified: 23-November-2009; 00:08 WST; adrian

This document outlines how to use ipfw and ipfw tables to implement WCCPv2 bypass and interception lists under recent FreeBSD releases.


The Cisco WCCPv2 design pushes much of the intelligence on to the "cache engines" (or any server doing packet inspection and rewriting - eg, an IDS, or some DoS mitigation service.)

This generally means that fine-grained ACL support for redirection is not always well implemented on the router. There are typically platform-specific limitations as to what can be filtered and redirected.

FreeBSD ipfw Overview

The simplest way to hijack and intercept requests is using ipfw. The main advantage ipfw has over alternative interception methods is that it does not require extra state to be kept per connection.

FreeBSD's ipfw support includes "table" support in later releases. This table support allows rules to apply based on multiple IP addresses or subnets instead of a single address per rule.

Example ipfw script

The following script implements three tables.

  • table 1 is an explicit client redirect list
  • table 2 is the server bypass list
  • table 3 is a client bypass list.

Table 3 is checked before table 1 - so more specific client bypass rules can be added rather than having to potentially fragment the client redirect list.

Please note that this script implements rules and sysctl's required to support the FreeBSD 7.x TPROXY patch for transparent client and server side interception (ie, client IP address spoofing.)



${fwcmd} -f flush

# table 1 - redirect client list
${fwcmd} table 1 flush
# table 2 - bypass server list
${fwcmd} table 2 flush
# table 3 - bypass client list
${fwcmd} table 3 flush

# ok, add local networks
#${fwcmd} table 1 add
#${fwcmd} table 1 add
#${fwcmd} table 1 add

# Allow direct connections
${fwcmd} add 10 allow tcp from any to ${localip} 80 in via ${myif}

# bypass list - server
${fwcmd} add 15 allow tcp from any to 'table(2)' 80 in via ${myif}
${fwcmd} add 16 allow tcp from 'table(2)' 80 to any in via ${myif}
# bypass list - client
${fwcmd} add 17 allow tcp from 'table(3)' to any 80 in via ${myif}
${fwcmd} add 18 allow tcp from any 80 to 'table(3)' in via ${myif}

# redirect non-me :80
${fwcmd} add 20 fwd,3138 tcp from 'table(1)' to any 80 in via ${myif}
# redirect client-destined packets on port 80 to me for local socket check
${fwcmd} add 30 fwd tcp from any 80 to 'table(1)' in via ${myif}

# pass the rest
${fwcmd} add 65000 allow ip from any to any

sysctl net.inet.ip.fw.enable=1
sysctl net.inet.ip.forwarding=1
sysctl net.inet.ip.nonlocalok=1