Local/International Router

From TLUGWiki

(Redirected from Local/International/Router)
Jump to: navigation, search

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.

Personal tools