|
Part 1 : Routing over two Internet connections with Linux Part 2 : Inbound routing with two internet connections
In part 2 of "Inbound and outbound routing with two internet connections" I promised I would upload the script that makes the whole thing possible. So finally, here it is!
Now, If I was reading this I would think "Hey! sod reading all that crap about how it works! why dont I just download this script and hey presto!" and who can blame? But I really do recommend you read them (of course Im going to say that, I wrote them!) but in order to understand what the script does, and why, you really need to read both parts. I put the script together myself, admitedly with a lot of help from this page. but ultimately, there's nothing better for understanding a subject that sitting down getting your head around it. So download and enjoy! A few things to remember:
- IP addresses in the script have been changed to protect the innocent.
- The script also starts the openswan ipsec server on the router - which I havent really mentioned in either article (Sorry!)
- Alot of the ip rules and routes are added using a function which first checks to see if the rule or route already exists. This means that the Script settings can be changed and run again without having to reboot
- All of the functions Ive mentioned are near the top of the script
- All of the variables you'll need to change are at the very top of the script
- Ive commented fairly well to make it easier to follow
- Thats it.
Enough of my ramblings! Here it is
A bit more
One of the features of IPtables is that it allows dynamic insertion and deletion of rules without having to reload it. So lets say (as happened to me last week) Internet connection B goes down. (Either in part or in whole) and all http traffic (80) is going out via this connection (B) we have two choices:
- Load up our router script and change the routetraffic commands to route http traffic over A and reload the script, this will of course disconnect anyone who has any other connection open and still functioning over internet connection B (shouty telephone conversations ensue)
- Change the rules dynamically to route http traffic over internet connection A, maintaining the existing connections which already exist on A, and generally contribute to a more peacful work environment
I consider myself more of a pacifist, so I think the second one is the best. How can we do this? Well a small amount of routing in the IPTABLES manual gave the answer (fairly obvious to you IPTABLES experts out there I imagine).
Lets have a look at the commands we'll use....
If A is the primary connection, and http traffic was being routed over B (the secondary) there will be a rule in the PREROUTING:mangle table stating that any incoming (to the routing from from either internal network) http (80) traffic should be marked. This will then be picked up by the ip rules and routed over the alternate routing table, and thus out on internet connection B. You can list the contents of the PREROUTING:mangle table by issuing:
iptables -L PREROUTING -t mangle
You should see something like
MARK tcp -- <internal ip address range> anywhere tcp dpt:http MARK set 0x4
this is the rule which tells iptables to mark packets for transfer over the secondary connection. If the packet is destined to be routed over the primary connection, then no rule need exist. Ergo, the next step is to remove the rule from the table. This can be done with the following command
iptables -t mangle -D PREROUTING -p tcp --dport 80 -s 192.168.1.0/24 -j mark --set-mark 4
which will delete the rule from the table mangle which was marking http (80) traffic originating in our (internal) repro network which has a range of 192.168.1.x. From the moment you pressed enter to issue the above command, http traffic would now be routed over the primary connection. Problem solved.
If you have the opposite situation (e.g. you WANT to route traffic over the secondary connection) then simply append the rule to the PREROUTING:mangle table using
iptables -t mangle -A PREROUTING -p tcp --dport 80 -s 192.168.101.0/24 -j mark --set-mark 4
Again, changes are instantainous.
Web based traffic routing
I had written a script to allow on the fly changes to the traffic routing. The idea being that you could choose a port number, protocol type, and an internet connection, and have it route the traffic accordingly. It certainly saved on ssh'ing the router! However, since the move over to Joomla 1.5 I seem to have misplaced it. Ill probably get around to finding it eventually.
A rather useful application of the above is to incorporate the above into a script, which allows you to switch between internet connections on a per-traffic type basis. Im working on a script at the moment which will do just that, and obviously post it up here when I get chance. As a temporary back stop, Ive written a short script in php which serves the purpose for the time being. Basically, its acts like a flipper switch for a given traffic type. So sticking with our http example, the script simply runs the command to list the mangle table and greps it for the rule to mark http packets. If it finds such a rule, it deletes it. If not, it appends it to the mangle table. Thus calling the script will simply flip the traffic from one connection to the other.
Now I wanted to be able to call this script from a web page, which immediatley causes a problem for two reasons:
-
Generally speaking, the httpd or apache user doesnt have rights to alter the iptables on its host machine (quite rightly so)
-
My webserver is a different box to the router
SSHing the router from the webserver seemed the most logical work around, but how to get the password entered into the ssh command when it prompts for one? Expect proved to be answer (you can check it out here) which is designed for such occasions. basically you write a script which tells it what to expect (do you see what they did there?) and it inputs whatever you ask it to. Next I found this expect script which accepts a host, the root password, and a command: (thanks to the chaps at NIXCraft for that)
#!/usr/bin/expect -f # Expect script to supply root/admin password for remote ssh server # and execute command. # This script needs three argument to(s) connect to remote server: # password = Password of remote UNIX server, for root user. # ipaddr = IP Addreess of remote UNIX server, no hostname # scriptname = Path to remote script which will execute on remote server # For example: # ./sshlogin.exp password 192.168.1.11 who # ------------------------------------------------------------------------ # Copyright (c) 2004 nixCraft project <http://cyberciti.biz/fb/> # This script is licensed under GNU GPL version 2.0 or above # ------------------------------------------------------------------------- # This script is part of nixCraft shell script collection (NSSC) # Visit http://bash.cyberciti.biz/ for more information. # ---------------------------------------------------------------------- # set Variables set password [lrange $argv 0 0] set ipaddr [lrange $argv 1 1] set username [lrange $argv 2 2] set timeout -1 # now connect to remote UNIX box (ipaddr) with given script to execute spawn ssh $username@$ipaddr match_max 100000 # Look for passwod prompt expect "*?assword:*" # Send password aka $password send -- "$password\r" # send blank line (\r) to make sure we get back to gui send -- "\r" expect eof
Copy the above lines into a file called flip.exp and then chmod +x flip.exp to allow it to be executed (otherwise you'll get a Permission denied error)
This script can then be called from your web page using (in php)
exec("flip.exp <root password> <ip_address_of_router> <location of flip sh script>");
Easy! Like I said, Ive got a php script that performs the actually flipping at the moment. I'll get around to converting this into sh and when I do Ill post it up here. There seems to be a lot of interest in routing over multiple internet connections, so thanks everyone for your continued support.
|