Local/International Router
From TLUGWiki
Contents |
[edit] Introduction
As you know Internet Usage in South Africa costs fortunes. So some poeple have gotten this amazing idea: Let's route Local traffic with one local-only(IS backbone) account and all the international traffic with another one(most likely SAIX).
This is done with the help of PPPOE(in my case), so your current router will not be used to dail your account by itself. Currently I don't know how to know set it up with a modem connected directly to one's computer.
For windows user the solutions is in the form of RouteSentry.
Please note that this howto is gentoo-based, I'm sure it could be easily applied to most distros. For further details on how the gentoo works in general see the Gentoo Wiki
[edit] Your Router
Since there are so many different routers this is up to you to figure out. What you have to do is change your router to Bridged mode.
Alias: RFC1483-Bridge LLC Pure Bridge LLC Bridge
[edit] The required modules
For ppp/pppoe support(using menuconfig):
Device Drivers --->
Network Device Support --->
<M> PPP (point-to-point protocol support
<M> PPP over Ethernet (EXPERIMENTAL)
For masquerading(aka router) support:
Networking --->
Networking Options --->
[*] Network packet filtering(replaces ipchains)
IP: Netfiler Configuration
<M> Full NAT
<M> MASQUERADING target support
<M> REDIRECT target support
(or * if you do not want a module)
Note: REDIRECT is only necessary if you want to use a transparent proxy or want to forward ports etc.
[edit] route lookup algorithms
The kernel implements two different route lookup algorithms. Unless you are running a relatively busy system the default FIB_HASH algorithm should be fine. If however you feel that routing is taking too long (remember linux implements a route cache which reduces the required number lookups) you might want to try out FIB_TRIE.
Networking --->
Networking Options --->
[*] IP: advanced router
Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure) (FIB_HASH) --->
[edit] Setting up pppd
[edit] Installing the required programs
If you have your kernel setup to be able to dial over ethernet you have to setup the userland utilities.
The required packages are ppp, rp-pppoe and all the equivalent packages on your distro.
#emerge -av rp-pppoe ppp
[edit] Configuration
You now have the utilities but nothing more. You have to edit your /etc/conf.d/net to setup the devices. Here is what mine looks like:
| File: /etc/conf.d/net |
# This blank configuration will automatically use DHCP for any net.*
# scripts in /etc/init.d. To create a more complete configuration,
# please review /etc/conf.d/net.example and save your configuration
# in /etc/conf.d/net (this file :]!).
config_eth0=( "192.168.1.101 netmask 255.255.255.0" )
#PPP - setup for the split connection.
#ppp0 will be my local connection.
config_ppp0=("ppp")
link_ppp0="eth0"
plugins_ppp0=("pppoe")
username_ppp0='xxxxx@xxxisdsl.net'
password_ppp0='xxxx'
pppd_ppp0=("usepeerdns")
#ppp1 will be my international connection.
config_ppp1=("ppp")
link_ppp1="eth0"
plugins_ppp1=("pppoe")
username_ppp1='xxxxxx@telscum.co.za'
password_ppp1='xxxx'
pppd_ppp0=("usepeerdns" "defaultroute")
|
I'm the only user on my machine, so I don't mind me seeing the account details, if you don't want this try:
# chmod a-r /etc/init.d/net
There are ways to hide one's password (see /etc/conf.d/net.example). For more options please see the /etc/conf.d/net.example.
Furthermore you should symlink net.lo to net.ppp0 and net.ppp1 (older versions of baselayout had a seperate net.ppp0 - delete it):
# ln -s /etc/init.d/net.eth0 /etc/ini.d/net.ppp0 # ln -s /etc/init.d/net.eth0 /etc/ini.d/net.ppp1
To start the connections, just run.
# /etc/init.d/net.ppp0 start # /etc/init.d/net.ppp1 start
If you have started it go to tty12 or
# tail /var/log/messages
and you should see some form of your connections setting up:
Jan 2 14:53:23 bismarck pppd[15939]: Plugin passwordfd.so loaded. Jan 2 14:53:23 bismarck pppd[15939]: Plugin rp-pppoe.so loaded. Jan 2 14:53:23 bismarck pppd[15939]: RP-PPPoE plugin version 3.3 compiled against pppd 2.4.4 Jan 2 14:53:23 bismarck pppd[15939]: pppd 2.4.4 started by jacques, uid 0 Jan 2 14:53:23 bismarck pppd[15939]: PPP session is 46810 Jan 2 14:53:23 bismarck pppd[15939]: Using interface ppp0 Jan 2 14:53:23 bismarck pppd[15939]: Connect: ppp0 <--> eth0 Jan 2 14:53:24 bismarck pppd[15939]: PAP authentication succeeded Jan 2 14:53:24 bismarck pppd[15939]: peer from calling number 00:12:80:2D:5F:A8 authorized Jan 2 14:53:24 bismarck pppd[15939]: local IP address 196.209.76.118 Jan 2 14:53:24 bismarck pppd[15939]: remote IP address 196.209.64.1 Jan 2 14:53:24 bismarck pppd[15939]: primary DNS address 168.210.2.2 Jan 2 14:53:24 bismarck pppd[15939]: secondary DNS address 196.14.239.2
[edit] Seperating log info
I've found it useful to log my pppd logs seperately. I use syslog-ng(other syslogs should be similiar). Just edit /etc/syslog-ng/syslog-ng.conf to contain these lines:
| File: /etc/syslog-ng/syslog-ng.conf |
log { source(src); destination(messages); };
log { source(src); destination(console_all); };
destination ppp { file("/var/log/ppp.log"); };
filter f_ppp { program(pppd); };
log { source(src); filter(f_ppp); destination(ppp); };
|
[edit] The route Script
The script provided here is capable of pulling the routes from a public, telnet accessible bgp server such as route-server.is.co.za. It also has a few other advantages over the previous inside /etc/ppp/ip-up script we had here, and a few things which that script did NOT do. A few features of the script here:
- It won't add routes that may be required in order to obtain the information (DNS + routes to server).
- It doesn't need to be called from ip-up .. it can be run at any time.
- Caching of the routes available on the server, the period isn't parameter configurable, but can be adjusted in the script (720 == 12 hours).
- If it fails to obtain the routing info from the bgp server it should fall back to the cache (not tested).
Before you can use this script you need to create it's caching directory, /var/lib/bgp_route_cache, after that this script needs to be run as root, the example inside the script should be sufficient.
| File: routes_add_bgp_via.sh |
#! /bin/bash
bgp_server=$1
shift
route_spec=("$@")
[ -z "${bgp_server}" ] && echo -e "USAGE: $0 bgp_server route spec\neg: $0 route-server.is.co.za dev ppp0" && exit -1
[ -z "${route_spec}" ] && echo -e "USAGE: $0 bgp_server route spec\neg: $0 route-server.is.co.za dev ppp0" && exit -1
ip=/sbin/ip
nc=/usr/bin/nc
awk=/usr/bin/awk
dos2unix=/usr/bin/dos2unix
find=/usr/bin/find
cacheperiod=720
routes_file=/var/lib/bgp_route_cache/${bgp_server}
need_update=$($find "${routes_file}" -mmin "${cacheperiod}" | wc -l)
trap "rm -f '${routes_file}.tmp'" EXIT
[[ $need_update -gt 0 ]] && echo -e "terminal length 0\nshow ip bgp\nexit" | $nc "${bgp_server}" 23 | $dos2unix | awk '/^*/ {print $2}' | \
awk -F'[./]' '{ printf $0;
if (NF==5) {
print ""
} else {
if ($1 < 128) {
print "/8"
} else if ($1 < 192) {
print "/16"
} else {
print "/24" }
}
}' > "${routes_file}.tmp"
[[ $(wc -l "${routes_file}.tmp") -gt 0 ]] && mv "${routes_file}.tmp" "${routes_file}"
exec 4<"${routes_file}"
while read subnet <&4; do
$ip route add "${subnet}" "${route_spec[@]}"
done |
Right, so obviously we need to actually use this, so let's take a look at how I personally use this atm:
| File: /etc/ppp/ip-up |
#!/bin/bash
# this is a script which is executed after connecting the ppp interface.
# look at man pppd for details
# the followings parameters are available:
# $1 = interface-name
# $2 = tty-device
# $3 = speed
# $4 = local-IP-address
# $5 = remote-IP-address
# $6 = ipparam
# <b>IMPORTANT</b>: This assumes you're running dnscache (from djbdns) for your internal DNS
# Otherwise you need to use the normal distro-provided scripts.
if [ "${USEPEERDNS}" ]; then
DNSFILE="/etc/ppp/dns-${IFACE}"
>"${DNSFILE}"
for dns in DNS1 DNS2; do
if [ -n "${!dns}" ]; then
echo "${!dns}" >> "${DNSFILE}"
/sbin/ip route add ${!dns}/32 dev ${IFNAME}
fi
done
cat /etc/ppp/dns-* > /var/dnscachex/root/servers/@
/usr/bin/svc -h /service/dnscachex
fi
# Standard Gentoo stuff to notify the RC system that the device has come up...
# not sure how this works but it does.
if [ -x /etc/init.d/net.$1 ]; then
if ! /etc/init.d/net.$1 --quiet status ; then
export IN_BACKGROUND="true"
/etc/init.d/net.$1 --quiet start
fi
fi
# Any device specific commands goes in here...
case "${IFACE}" in
ppp0)
# Local
/sbin/ip route add $(dnsip route-server.is.co.za)/32 dev ${IFACE}
/usr/local/sbin/routes_add_bgp_via.sh route-server.is.co.za dev ${IFACE}
;;
ppp1)
# International
;;
esac
# And the normal ip-up.local stuff
[ -f /etc/ppp/ip-up.local ] && . /etc/ppp/ip-up.local "$@" |
This potentially leaves some extra routes in your routing cache, frankly, I don't care, it'll be two extra routes for every ppp connection, and one for the bgp server. Compared to the 988 (currently, 2007/04/02) routes that we're throwing in anyway for the local/international splitting, 5 extra routes is negligible imho.
Note that I opted to just hack /etc/ppp/ip-up and get it over with since it was stuffing around with my DNS configurations. Normally you should add changes to /etc/ppp/ip-{up,down}.local
[edit] iptables and Masquerading
Masquerading is the easy part, we need a single rule:
iptables -t nat -A POSTROUTING -o ppp+ -j MASQUERADE
This will enable masquerading on all outbound connections that leave the box via any ppp device.
A very simplistic firewall that should be good enough for most people follows:
iptables -A INPUT -m state --state invalid -j DROP
iptables -A INPUT -m state --state related,established -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i eth+ -j ACCEPT
iptables -P INPUT DROP
iptables -A FORWARD -m state --state invalid -j DROP
iptables -A FORWARD -m state --state related,established -j ACCEPT
iptables -A FORWARD -i eth+ -o ppp+ -j ACCEPT
iptables -P FORWARD DROP
A couple of notes:
- Route hack protection is implicit (people can't bounce packets between your ppp devices).
- protocol tracking. The above setup will correctly handle ftp data connections, irc dcc connections and a few others permitting the modules are loaded.
- Everything on eth* is trusted, nothing on ppp* is trusted.
- There is a limit on the tracking of connections, this limit depends on the amount of RAM you have, it's possible to change this limit by using kernel parameters (With 128MB of ram it defaults to approx 16 000 connections so I don't see too many people having problems).
- The above does not protect against people sending packets from addresses like 127.0.0.1 - that is already covered by rp_filter which means "marsian" packets gets filtered before we even get to iptables.
[edit] Transparent Proxy
[edit] Squid configuration
I use squid but any other proxies could be used.Another favourite of mine is adzapper(which is a proxy-side addblocker).
#emerge -av squid adzapper
Then you'll want to configure your /etc/squid/squid.conf according to your needs. These few lines are rather important:
| File: /etc/squid/squid.conf |
http_port 3128 transparent #grant access http_access allow localhost acl localnet src 192.168.1.0/24 http_access allow localnet #cache specifics cache_dir aufs /var/cache/squid 512 16 256 #rotate my logfiles. logfile_rotate 10 #To make use of adzapper url_rewrite_program /etc/adzapper/wrapzap url_rewrite_children 10 |
These are just the basic and definately don't include all, open /etc/squid/squid.default and see for yourself what I'm referring to.
After all is setup according to your needs, you can test your proxy:
#/etc/init.d/squid start
You'll probably want to add it to the start up.
#rc-update squid default
The to test simple go to your browser, put in 127.0.0.1(or the box which is your router) and your http_port(default:3128) under Connections Settings. You should then be able to browse. If not check wether your port is actually open with:
#nmap localhost -p 3128
[edit] iptables
You need to add a DNAT rule to iptables in order to make it all work:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.1.101:3128
Replace the ip:port pair as appropriate for you. I'm not sure whether it's possible to use 127.1 here, it just might work. squid listens on port 3128 by default.

