This is a small HOWTO about doing source routing with Squid and Linux. With Squid you can specifiy the outgoing IP address using ACLs. That means that you can select the outgoing IP using the information inside HTTP messages, thing that you can’t do with a firewall. The syntax is simple:
acl somedomain dstdomain somedomain.com
tcp_outgoing_address 188.8.131.52 somedomain
Those two lines say: “If the request is asking for somedomain.com, go to the world using IP 184.108.40.206”.
Now the Linux part. If you have more than one public IP address and you want to make the Squid configuration to work you need some iproute lines.
ip rule add table 10 from 220.127.116.11
ip route add table 10 default via GW
And those two lines says: “If the source IP of the packaet is 18.104.22.168, go via GW”.
Source routing with Linux is simple. What you do is to create a new table. This table will be used by that packets that match the criteria specified in “ip rule”. The “default table” is the table main, everything goes there if there is no rule. Is the table that you see with “ip route” or “route -n” (please, don’t use the last command anymore).
Today chatting via IRC I remembered a problem that I had some years ago with virtualization, iptables, nat and bridge. The situation of the guy asking was pretty similar. He has a one virtual machine (Qemu/KVM) connected to the world using a bridge and its default gateway is the virtualization host. He was trying to apply destination NAT to the VM in the host machine but it didn’t work. The rule was simple:
iptables -t nat -A POSTROUTING -s 10.0.3.11 -o eth0 -j MASQUERADE
It is perfect, there is nothing wrong there but he never saw the packet in the POSTROUTING chain. Why? The quick answer is “packets don’t cross nat table twice”. There is a flag in the Linux bridge to enable filtering with Iptables. Packets go to Iptables in the kernel when they are forwarded by the bridge. This includes the NAT table.
In the bridging process, you don’t know the outgoing interface so the previous rule doesn’t work. He needs the interface because he’s using MASQUERADE. In the routing process, the packets go to iptables but they never cross NAT tables because the packet already crossed the table in the bridging process.
How can we fix this? There are two options I think:
- echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables #To disable Iptables in the bridge.
- Raw table: Some years ago appeared a new tables in Iptables. This table can be used to avoid packets (connection really) to enter the NAT table: iptables -t raw -I PREROUTING -i BRIDGE -s x.x.x.x -j NOTRACK.
If you still don’t understand why this happens, I’ll try to explain one more thing. If you have an scenario with Virtualization and you host is your gateway, the packets follow this steps: [VM]->[bridge]->[virtual interface]->[host]->[physical interface]->[net]. When they cross the host, you have the routing process there.