Route Squid Proxy Traffic Through an OpenVPN Gateway

From nikosapi.org wiki
Revision as of 01:09, 2 March 2014 by Nikosapi (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Problem Description

When using a VPN, the default configuration is to route all traffic over the VPN tunnel. However, there are some instances where it is useful to only route application-specific traffic instead of forcing all traffic through the VPN. This isn't always possible, but if application in question supports an HTTP proxy then we can use Squid to transparently pass that traffic off to an OpenVPN gateway.

Implementation Details

iproute2 Configuration

Permanently add a custom routing table for OpenVPN traffic:

echo "100 openvpn" > /etc/iproute2/rt_tables

The addition/deletion of the actual routes will be added by the OpenVPN up/down scripts.

Squid Configuration

Traffic which is accepted by Squid must be emitted on the OpenVPN tunnel interface in order for this to work. Since IP address for the interface is dynamic (assuming the server is not configured to provide static IP addresses) this would require updating the Squid config file every time the VPN connection is established (AFAIK, a hostname cannot be provided in place of the IP address). To get around this limitation, we will emit traffic on a random IP address and then use iptables to forward traffic to the real IP address.

The following lines were added to the /etc/squid3/squid.conf config file:

acl local_net src 192.168.0.0/255.255.255.0
http_access allow local_net
forwarded_for delete
tcp_outgoing_address 10.202.101.1

The first line defines my local network, the second line instructs Squid to accept connections from any computer on my local network, and the third line prevents Squid from including the X-Forwarded-For header in its outgoing connections. The last line defines the source IP address for which Squid will use to make requests on behalf of users. Note that this IP address should not belong to your local subnet or the OpenVPN subnet.

OpenVPN Client Configuration

Add the following items to the client config file:

route-noexec
route-up route-up.sh
down down.sh

The route-noexec parameter prevents the client from applying the default routing configuration which is pushed from the server. The route-up parameter must point to a script which will be used to setup the custom routing and the down parameter must point to a script that will remove the custom routing once the VPN client is stopped.

The content of route-up.sh should look like this:

#!/bin/bash

source "`dirname $0`/vpn_config.sh" 

logger "OpenVPN route-up.sh: bridge if: $VPNBRIDGE_IF addr: $VPNBRIDGE_ADDR table: $VPNBRIDGE_TBL"

# Add the default route to our custom 'openvpn' routing table
ip route add default via $ifconfig_remote dev $dev table $VPNBRIDGE_TBL

# Add new interface to act as a middleman between the fixed address used 
# by Squid and the dynamic address provided by OpenVPN
ip tuntap add dev $VPNBRIDGE_IF mode tun
ip addr add $VPNBRIDGE_ADDR dev $VPNBRIDGE_IF
ip link set dev $VPNBRIDGE_IF up

# All packets from Squid are passed to the custom routing table
ip rule add from $VPNBRIDGE_ADDR lookup $VPNBRIDGE_TBL

# Rewrite the source address to match the one provided by OpenVPN
iptables -t nat -A POSTROUTING -s $VPNBRIDGE_ADDR -j SNAT --to-source $ifconfig_local

logger "OpenVPN route-up.sh: local: $ifconfig_local remote: $ifconfig_remote device: $dev"

The content of down.sh should look like this:

#!/bin/bash

source "`dirname $0`/vpn_config.sh"

logger "OpenVPN down.sh: bridge if: $VPNBRIDGE_IF addr: $VPNBRIDGE_ADDR table: $VPNBRIDGE_TBL openvpn local: $ifconfig_local"

ip rule del from $VPNBRIDGE_ADDR lookup $VPNBRIDGE_TBL
iptables -t nat -D POSTROUTING -s $VPNBRIDGE_ADDR -j SNAT --to-source $ifconfig_local
ip tuntap del dev $VPNBRIDGE_IF mode tun

Finally, the common configurable parameters for both of these scripts is found in another script named vpn_config.sh. Its contents should look like this:

#!/bin/bash

export VPNBRIDGE_IF=vpnbridge0
export VPNBRIDGE_ADDR=10.202.101.1
export VPNBRIDGE_TBL=openvpn

These three scripts should be placed in the same directory and must be marked as executable (chmod +x).