Thursday 7 July 2016

Setting up a transparent proxy with squid and an ASA

Important Note: To stop you banging you head against a wall - please note that the WCCP server (ASA in this case) and the cache / client (squid in this case) should be on the SAME subnet otherwise WCCP will not function correctly!

Because the ASA automatically picks the WCCP router ID (picks the highest interface) - the router ID is where the ASA will send the GRE traffic from. You have to ensure that the cache can communicate with this subnet. I believe with later version of IOS you can manually define the router ID.

Firstly define your proxy server(s):

access-list wccp-servers extended permit ip host any

and the client range:

access-list wccp-clients extended deny ip host any
access-list wccp-clients extended permit tcp host <client ip> any eq 80
access-list wccp-clients extended deny ip any any

and then assign them to WCCP:

wccp web-cache redirect-list wccp-clients group-list wccp-servers

Enable WCCP version 2 (not required on some older IOS versions):

wccp version 2

and finally enable it on the relevent interface:

wccp interface inside web-cache redirect in

wccp interface inside 70 redirect in

Note: ('70' is a dynamic service number and represents HTTPS traffic in this case.)

** Very important: Verify what the 'Router Identifier' is that of your INSIDE interface (it takes the highest IP address of your interfaces by default) as that the 'Router Identifier' specifies where the GRE packets will originate from and if it selects another interface e.g. DMZ - and the interface is unable to access the squid server the GRE tunnel will fail! **

Install squid with:

sudo yum install squid

ensure it starts on boot:

sudo systemctl enable squid

We need to ensure that the squid installation we have has compiled with the following flags:

--enable-linux-netfilter and --enable-wccpv2

To verify we can issue something like:

squid -v

WCCP Squid Configuration

Add the following to /etc/squid/squid.conf:

# WCCP Router IP

# forwarding
wccp2_forwarding_method gre

# GRE return method
wccp2_return_method gre

# ensures that wccp is not enabled during a cache rebuild
wccp2_rebuild_wait on

# used for load balancing purposes
wccp2_weight 10000

# Assignment method hash|mask
wccp2_assignment_method hash

# standard web cache, no auth
wccp2_service standard 0

# the following defines HTTPS
wccp2_service dynamic 70
wccp2_service_info 70 protocol=tcp flags=src_ip_hash,src_port_alt_hash priority=240 ports=443

Option A: MITM HTTPS Proxy

This is where HTTPS requests will be intercepted by the proxy and we can then decrypt the streams to see exactly what users are doing - however the downside of this is that you must deploy a self-signed CA certificate to your users in order for this to work correctly.

We will need to generate a new CA for dynamic certification creation to work properly:

mkdir -p /etc/squid/cert && cd /etc/squid/cert
openssl req -new -newkey rsa:2048 -sha256 -days 1095 -nodes -x509 -extensions v3_ca -keyout squidCA.pem -out squidCA.pem

We add / amend the following to the squid configuration:

http_port 3128 ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=8MB cert=/etc/squid/cert/squidCA.pem
http_port 3126 intercept
https_port 3127 intercept ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=8MB cert=/etc/squid/cert/squidCA.pem

Note: Make sure that your SSL certificate cache path is in the appropraite location otherwise SELinux will likely complain and squid will fail to start.

sslcrtd_program /usr/lib64/squid/ssl_crtd -s /usr/lib64/squid/ssl_db -M 50MB
sslcrtd_children 5

Note: You should also ensure that the certificate is installed on each client machine - e.g. deployed through group policy.

Option B: Direct HTTPS Proxy

This is my preferred option - and works pretty well if you use DNS to block nasty sites rather than inspecting it when it traverses the proxy.

http_port 3128 ssl-bump cert=/etc/squid/cert/squidCA.pem
http_port 3126 intercept
https_port 3127 intercept ssl-bump cert=/etc/squid/cert/squidCA.pem

ssl_bump none all
sslcrtd_program /usr/lib64/squid/ssl_crtd -s /usr/lib64/squid/ssl_db -M 50MB
sslcrtd_children 5

But before we start squid we should ensure that the certificate cache is initialised:

mkdir -p /var/lib/squid

/usr/lib64/squid/ssl_crtd -c -s /usr/lib64/squid/ssl_db

and the user running squid has access the directory:

chown -R <squid-user>:<squid-user> /usr/lib64/squid/ssl_db

And then we will need to create a pseudo interface for our GRE tunnel on our squid server:

vi /etc/sysconfig/network-scripts/ifcfg-wccp0


Note: The outer tunnel address does not matter with WCCP!

and bring it up:

ip link set wccp0 up

and on the ASA issue the following to ensure the proxy and ASA are communicating:

debug wccp packets

You should see something like:

WCCP-PKT:S00: Received valid Here_I_Am packet from w/rcv_id 00001AF0

WCCP-PKT:S00: Sending I_See_You packet to w/ rcv_id 00001AF1

Proceed by setting up ip forwarding, reverse path filter etc.:

sudo vi /etc/sysctl.conf

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.ip_forward = 1

and ensure changes persist:

sysctl -p

And add relevent rules to forward traffic from port 80 to 3128:

sudo iptables -A INPUT -p tcp -m tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -m tcp -p tcp --dport 3128 -j ACCEPT
sudo iptables -A INPUT -i eno123 -s <router-identifier-id> -d <squid-proxy-ip> -p gre -j ACCEPT

sudo iptables -t nat -A PREROUTING -i wccp0 -p tcp -m tcp --dport 80 -j DNAT --to-destination <squid-ip>:3126
sudo iptables -t nat -A PREROUTING -i wccp0 -p tcp -m tcp --dport 443 -j DNAT --to-destination <squid-ip>:3127
sudo iptables -t nat -A POSTROUTING -o eno123 -j MASQUERADE

Then restart squid and run tcpdump:

sudo service squid restart
tcpdump -i eno123 udp and port 2048

you should see a similar output too:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno123, link-type EN10MB (Ethernet), capture size 65535 bytes
15:43:55.697487 IP > UDP, length 144
15:43:55.704418 IP > UDP, length 140
15:44:05.697649 IP > UDP, length 144
15:44:05.704967 IP > UDP, length 140
15:44:10.704542 IP > UDP, length 336

and you should also see GRE packets on the main interface:

tcpdump -i eno123 proto gre

** Both nodes communicate with each other via udp/2048 **

** Important: Also ensure that you see the RX counter on the tun0 interface increasing e.g.

ifconfig tun0

Now on your ASA we can issue:

show wccp

and you should notice that the 'Number of Cache Engines:' and 'Number of routers' has now showing as 1.

Now attempt to connect from the client:

telnet 80

Reviewing the tunnel device and the your NIC:

tcpdump -i wccp0 port 80

tcpdump: WARNING: wccp0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wccp0, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
14:55:29.026958 IP > Flags [S], seq 4203563477, win 29200, options [mss 1460,sackOK,TS val 4078141366 ecr 0,nop,wscale 7], length 0
14:55:29.027136 IP > Flags [S], seq 640886751, win 29200, options [mss 1460,sackOK,TS val 4078141366 ecr 0,nop,wscale 7], length 0
14:55:29.027235 IP > Flags [S], seq 2568663163, win 29200, options [mss 1460,sackOK,TS val 4078141366 ecr 0,nop,wscale 7], length 0
14:55:29.027345 IP > Flags [.], ack 692773047, win 229, options [nop,nop,TS val 4078141366 ecr 21645736], length 0

And then finally to see the content being forwarded to your client / ingress interface:

tcpdump -i eth0 host

14:57:20.593381 IP > Flags [S.], seq 4206693825, ack 3973858615, win 28960, options [mss 1460,sackOK,TS val 21757302 ecr 4078252932,nop,wscale 7], length 0
14:57:20.593507 IP > Flags [S.], seq 1070691703, ack 1857333684, win 28960, options [mss 1460,sackOK,TS val 21757302 ecr 4078252932,nop,wscale 7], length 0
14:57:20.607557 IP > Flags [.], ack 4079575675, win 270, options [nop,nop,TS val 21757316 ecr 4078252946], length 0
14:57:20.608243 IP > Flags [S], seq 3249023064, win 29200, options [mss 1460,sackOK,TS val 21757317 ecr 0,nop,wscale 7], length 0

14:57:20.696048 IP > Flags [S.], seq 3393942316, ack 3249023065, win 14480, options [mss 1380,sackOK,TS val 1828797864 ecr 21757317,nop,wscale 7], length 0

So the process flow is as follows:

- Client requests website (goes to default gateway / ASA)
- The ASA redirects the request (WCCP) to the proxy server over the GRE tunnel
- The proxy server receives the GRE traffic from it's physical interface and terminates it through our GRE interface
- The web traffic on the GRE tunnel is then redirected to our local proxy server - which serves the request
- When the local proxy server gets a reply it forwards the request directly out to the client (i.e. not via the GRE tunnel again) - in this case straight out of the client interface.



Post a Comment