On standard Internet systems, when you receive a packet and decide where to route it to, that decision is made only based on the destination of the packet.
In this, a simple routing table for a firewall, all traffic for 192.168.0.0/24 is routed out eth1; traffic for 10.7.0.0/24 is routed out eth0; and everything else is routed out ppp0 to the Internet.
However, let's deal with the situation where we have two interfaces ppp0 and ppp1 (a dual-homed situation, with two internet providers.) We will call the IP address on ppp0 $P0 and on ppp1, $P1.
If you get traffic for your machine come into ppp1 from $OUTSIDE, the machine will receive the packets, generate a reply, and the system will now have a packet from $P1, destined to $OUTSIDE. Because the system only looks at destination IP addresses, the packet will get routed out the default gateway, ppp0. Even if you disable ReversePathFiltering to allow this kind of traffic on all your interfaces, chances are high your ISP will be using it. (For example, TelstraClear does not allow any traffic on it's network that originates from another network's IP.)
So, this is where source based routing comes in. We need to take any traffic that originates from $P1 (replies to traffic that came in ppp1), and route it back out through ppp1.
To do this we need to have the iproute2 package, which provides the command /sbin/ip; giving you much finer grained control over routing. If you don't have the /sbin/ip command, install an iproute package (debian: apt-get install iproute). The command route cannot handle multiple routing tables.
You also need to have a couple of kernel options enabled: they are CONFIG_IP_ADVANCED_ROUTER (Networking/IP: Advanced Router) and CONFIG_IP_MULTIPLE_TABLES (Networking/IP: policy routing).
Then, what you do is you create another routing table by editing /etc/iproute2/rt_tables; in my example I wish to create routes for a jetstream connection, so I have called the table 'jetstream' 1? by adding the line
100 jetstream
Now, you can create a rule that dictates what routing table to look at.
ip rule add from $P1 table jetstream
Look at the rules with ip rule list to get an idea of what happens when a packet is to be routed. The important bit is the from $P1. If you forget it, depending at the priority of your table, you could send all traffic to that table by default. Now, when routing, a packet that comes from the IP address $P1 will be passed to the routing table 'jetstream' instead of the main routing table.
And you're done. In my case, I'm doing this on a ppp interface, so I only need the routes to exist when the interface is up; I've therefore added scripts for this to /etc/ppp/ip-up.d/ (ip-down.d contains ip rule del; I leave the table there - it's no harm if it's not called, but you could remove it with ip route del).
Thanks to PerryLorier for explaining this all to me, and to the
Linux Advanced Routing and Traffic Control HOWTO for filling in the detail; specifically
Routing for multiple uplinks/providers.
1? It's added at priority 100 so that you can add other tables either side of it later if you want.
One page links to SourceBasedRouting: