<hostname>
text is literal, it seems that dhclient expands this at the right time somehowThis is an old revision of the document!
Due to the wholesome failure of my ISP to do things in a nice way my ADSL router was rendered useless and I was forced to either setup my own router or be content with a single PC on the internet in a house of 6 computers… I chose to setup my own gateway.
See also Traffic Shaping
Notes to self on how I setup my home network.
Device | Notes |
---|---|
modem | ADSL modem with 1x phone line socket and 1x ethernet socket. Tends to get clogged for some reason (high latency, but connection stays up) |
gateway | Linux host with *one* network adaptor, and nothing much to do |
LAN | 4 or so PCs, Wii, Xbox, couple of Nintendo DS consoles, etc |
Here's how it works in practice when a PC is connected up:
It's a ZyXEL P-660R-D1 ADSL Modem.
The web interface is fairly limited, so enable the Telnet interface (Advanced → Remote MGMT → Telnet).
$ telnet 192.168.1.1 Trying 192.168.1.1... Connected to 192.168.1.1. Escape character is '^]'. Password: ****** Copyright (c) 1994 - 2007 ZyXEL Communications Corp. P-660R-D1> lan index 1 # Select LAN port 1 (of 1) enif0 is selected P-660R-D1> lan dhcp server gateway 192.168.1.2 P-660R-D1> lan save lan: save ok P-660R-D1> ip dhcp enif0 status DHCP on iface enif0 is server Start assigned IP address: 192.168.1.2/24 Number of IP addresses reserved: 192 Hostname prefix: dhcppc DNS server: 192.168.1.2 212.159.13.49 WINS server: 0.0.0.0 0.0.0.0 Domain Name : Default gateway: 192.168.1.2 Lease time: 259200 seconds Renewal time: 129600 seconds Rebind time: 226800 seconds Probing count: 4 slot state timer type hardware address hostname 0 UNCERTAIN 0 0 00 1 UNCERTAIN 0 0 00 2 UNCERTAIN 0 0 00 3 UNCERTAIN 0 0 00 ... Status: Packet InCount: 0, OutCount: 0, DiscardCount: 0 P-660R-D1> exit Connection closed by foreign host.
Changes are immediate, and persistent. Renew your DHCP lease to get the updated setting, and run route -n
to check the routing table, which should look like this:
$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0 0.0.0.0 192.168.1.2 0.0.0.0 UG 0 0 0 eth0
Important feature:
Desired routing table:
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.1.0 0.0.0.0 255.255.255.0 U 1 0 0 eth0 0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
Important features:
eth0
Desired DNS server list:
# Generated by NetworkManager nameserver 127.0.0.1 nameserver 192.168.1.1
Configuration files to edit:
/etc/dhcp3/dhclient.conf
1):
option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; send dhcp-requested-address 192.168.1.2; supersede domain-name "local robmeerman.co.uk"; supersede routers 192.168.1.1; prepend domain-name-servers 127.0.0.1; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers;
On-the-fly:
Taken from http://www.technize.com/2007/05/03/configuring-a-nat-gateway-in-linux/
echo 1 > /proc/sys/net/ipv4/ip_forward
Persistent:
Edit /etc/sysctl.conf:
# Uncomment the next line to enable packet forwarding for IPv4 net.ipv4.ip_forward=1
As you probably noticed from the physical topology diagram, there is only one network interface on the gateway PC, and so you may find that the gateway PC informs all of its clients that they can talk to the modem directly:
PING google.com (173.194.37.104) 56(84) bytes of data. From skuld.local (192.168.1.2): icmp_seq=1 Redirect Host(New nexthop: 192.168.1.1) 64 bytes from lhr14s02-in-f104.1e100.net (173.194.37.104): icmp_seq=1 ttl=57 time=15.4 ms
This can be disabled on-the-fly via:
echo 0 | sudo tee /proc/sys/net/ipv4/conf/*/accept_redirects echo 0 | sudo tee /proc/sys/net/ipv4/conf/*/send_redirects
Update 2013-10: This guide used to update /proc/sys/net/ipv4/conf/all/accept_redirects
, but now uses *
in place of all
. That was bad as the all
configuration merely sets the default, but won't alter any existing interfaces. Thanks to unix.stackexchange.com for this tip.
Or permanently by adding the following to /etc/sysctl.conf
:
net/ipv4/conf/all/accept_redirects = 0 net/ipv4/conf/all/send_redirects = 0
sudo aptitude install bind9
sudoedit /etc/bind/named.conf.options
forwarder
section and add ISP DNS server IPs: forwarders { 212.159.13.49; 212.159.13.50; };
sudo service bind9 restart
ikari.robmeerman.co.uk
(real public domain name) to a private IP. (This is not required if you have search robmeerman.co.uk
in /etc/resolv.conf
)sudoedit /etc/bind/named.conf.local
// LAN hosts zone "ikari.robmeerman.co.uk" { type master; file "/etc/bind/db.lan.ikari"; };
sudoedit /etc/bind/db.lan.ikari
; ; BIND data file for local area network (LAN) ; $TTL 604800 @ IN SOA ns.localhost. root.localhost. ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns.localhost. @ IN A 192.168.1.2 ; Zone's address * IN A 192.168.1.2 ; Wildcard (all sub-domains)
sudo aptitude install wondershaper # Assuming downlink == 3712 kbps / uplink == 448 kbps sudo wondershaper eth0 $((3712*1000)) $((448*1000))
I used to use Ubuntu's stock wondershaper
package, but now use my own adaptation of it that does *not* shape or police LAN traffic. This allows my gateway PC to double as a file server: internet traffic is shaped and policed to match my ADSL line speeds, while file-server (local) traffic runs at gigabit speeds.
#!/bin/sh # Adapted from http://lartc.org/wondershaper/ DOWNLINK=$2 UPLINK=$3 DEV=$1 if [ "x$DEV" = "x" ] then echo "Usage: $0 (DEV) [ 'clear' | (DOWNLINK UPLINK) ]" exit 0 fi # Display status when DOWNLINK/UPLINK are ommitted if [ "x$DOWNLINK" = "x" ] then tc -s qdisc ls dev $DEV tc -s class ls dev $DEV exit 0 fi # Clear both IN and OUT tc qdisc del dev $DEV root 2> /dev/null > /dev/null || true tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null || true if [ "x$DOWNLINK" = "xclear" ] then echo "Cleared traffic rules on $DEV" exit 0 fi ############################################################################### # UPLINK # Set root Queuing Discipline (qdisc) to Class Based Queuing (cbq) tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 1000mbit # Traffic is either headed to the gateway (i.e. internet traffic) or not. # Internet uplink is scarse, so aggresively shape it. LAN uplink is plentiful, # do not restrict it. # ============================================================================= # INTERNET GATEWAY: Shape to $UPLINK speed, this prevents huge queues in the # DSL modem that cause massive latency tc class add dev $DEV parent 1: classid 1:1 cbq rate ${UPLINK}kbit \ allot 1500 prio 5 bounded isolated # High priority internet traffic tc class add dev $DEV parent 1:1 classid 1:10 cbq rate ${UPLINK}kbit \ allot 1600 prio 1 avpkt 1000 # .. and its actual queue that holds the packets tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10 # Default priority internet traffic, bulk transfers. tc class add dev $DEV parent 1:1 classid 1:20 cbq rate $((9*$UPLINK/10))kbit \ allot 1600 prio 2 avpkt 1000 # .. and its actual queue that holds the packets tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10 # Low priority traffic. tc class add dev $DEV parent 1:1 classid 1:30 cbq rate $((8*$UPLINK/10))kbit \ allot 1600 prio 2 avpkt 1000 # .. and its actual queue that holds the packets tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10 # ============================================================================= # LAN tc class add dev $DEV parent 1: classid 1:40 cbq rate 1000mbit \ allot 1500 prio 5 borrow sharing tc qdisc add dev $DEV parent 1:40 handle 40: sfq perturb 10 # ============================================================================= # Filters # LAN traffic ----------------------------------------------------------------- tc filter add dev $DEV parent 1:0 protocol ip prio 1 u32 \ match ip dst 192.168.0.0/16 flowid 1:40 tc filter add dev $DEV parent 1:0 protocol ip prio 1 u32 \ match ip dst 10.0.0.0/8 flowid 1:40 tc filter add dev $DEV parent 1:0 protocol ip prio 1 u32 \ match ip dst 172.16.0.0/12 flowid 1:40 # Internet traffic ------------------------------------------------------------ # TOS Minimum Delay (ssh, NOT scp) in 1:10: tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \ match ip tos 0x10 0xff flowid 1:10 # ICMP (ip protocol 1) in the interactive class 1:10 so we # can do measurements & impress our friends: tc filter add dev $DEV parent 1:0 protocol ip prio 11 u32 \ match ip protocol 1 0xff flowid 1:10 # pablo.iranzo@uv.es provided a patch for the MLDonkey system # The MLDonkey uses small UDP packets for source propogation # which floods the wondershaper out. tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \ match ip protocol 17 0xff \ match ip sport 4666 0xffff \ flowid 1:30 # prioritize small packets (<64 bytes) tc filter add dev $DEV parent 1: protocol ip prio 12 u32 \ match ip protocol 6 0xff \ match u8 0x05 0x0f at 0 \ match u16 0x0000 0xffc0 at 2 \ flowid 1:10 #for a in $NOPRIOPORTDST #do # tc filter add dev $DEV parent 1: protocol ip prio 14 u32 \ # match ip dport $a 0xffff flowid 1:30 #done # #for a in $NOPRIOPORTSRC #do # tc filter add dev $DEV parent 1: protocol ip prio 15 u32 \ # match ip sport $a 0xffff flowid 1:30 #done # #for a in $NOPRIOHOSTSRC #do # tc filter add dev $DEV parent 1: protocol ip prio 16 u32 \ # match ip src $a flowid 1:30 #done # #for a in $NOPRIOHOSTDST #do # tc filter add dev $DEV parent 1: protocol ip prio 17 u32 \ # match ip dst $a flowid 1:30 #done # Internet traffic catch-all: bulk. tc filter add dev $DEV parent 1: protocol ip prio 18 u32 \ match ip dst 0.0.0.0/0 flowid 1:20 ############################################################################### # DOWNLINK # # Limit downloads to slightly less than the maximum achievable speed. This # prevents a queues building up in the ISP (which is typically a huge FIFO), # and so reduces round-trip time; effectively reducing latency. # Ingress policer # (FYI: The term "shaping" only applied to egress traffic, "policing" is the # ingress equivalent) tc qdisc add dev $DEV handle ffff: ingress # LAN traffic is exempt from policing tc filter add dev $DEV parent ffff: protocol ip prio 40 u32 \ match ip src 192.168.0.0/16 \ police pass \ flowid :1 tc filter add dev $DEV parent ffff: protocol ip prio 40 u32 \ match ip src 10.0.0.0/8 \ police pass \ flowid :1 tc filter add dev $DEV parent ffff: protocol ip prio 40 u32 \ match ip src 172.16.0.0/12 \ police pass \ flowid :1 # Internet traffic that arrives too fast should be discarded tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 \ match ip src 0.0.0.0/0 \ police rate ${DOWNLINK}kbit burst 10k drop \ flowid :1
sudo aptitude install squid
to install Squid v2.7.
Then edit /etc/squid/squid.conf
so that
http_port
tag is set to http_port 3128 transparent
http_access allow localnet
is uncommented
Restart Squid (sudo service squid restart
) and then foribly redirect web traffic to the proxy:
iptables -t nat -A PREROUTING ! -d 192.168.0.0/16 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3128
At first I didn't have a PC with two network cards, so I found a way to do it with one network card and a lot of ugly hacks and tricks. Sadly I did this long before I wrote this page, so I can't recall the details. But for those having similar problems here was my solution.
I use WinXP on my laptop, and happened to have a copy of VMware2) installed so I setup a new virtual machine with two NICs and inserted my trusty Knoppix Linux LiveCD3). Once booted I used the Linux IP Masquerade HOWTO to get things going.
Amazingly, this worked! I had 3 IPs on one NIC: 2 for the virtual machine running Knoppix, and 1 for Windows itself. Actually, IIRC, all 3 actually had seperate MAC addresses too.
I didn't keep this setup for long, as my laptop is portable and I didn't want it tied to the house.
The famous (perhaps even “standard”) way of making a Linux platform into a NAT router is to use a script called rc.firewall-iptables
from the Linux IP Masquerade HOWTO. While this definately works, it's a bit tricky to use, especially adding new port-forwarding rules which is something I do fairly regularly.
So I spent an afternoon doing a bit of BASH scripting and, based on the original script, produced the script below, which I hope some will find useful.
Download rc.firewall (14kB)
Well, it has a very nice block where you can set up portforwarding via simple lists using the Windows computer names, which means that if your network using DHCP and the IP addresses of your computers change sometimes, you'll have no problem if you simply schedule the script to run periodically. It also is nice in that it closes ports when the computer they are being forwarded to is offline.
Example of configuration block of script:
EXTIP=`ifconfig eth0 | egrep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n1` echo " External IP detected as $EXTIP"; # Local services exposed LOCALTCPPORTS="22" LOCALUDPPORTS="" # PCs to forward connections to, using names in /etc/hosts or NetBIOS PORTFWPC[0]="Ikari" TCPPORTS[0]="80 26346 113 4899 1024 5190" UDPPORTS[0]="26346" PORTFWPC[1]="Kirara" TCPPORTS[1]="5443 2902 56881" UDPPORTS[1]="2902 56881" PORTFWPC[2]="Mum" TCPPORTS[2]="4662 26346" UDPPORTS[2]="4672 26346"
Notes
eth0
, my first network interface card (NIC), and the IP address changes when we have a power-cut or my ISP decides to cut us due to bad managment and faulty hardware Running the script will produce output like so:
Loading simple rc.firewall version 0.78.. External Interface: eth0 Internal Interface: eth1 loading modules: ---------------------------------------------------------------------- ip_tables, ip_conntrack, ip_conntrack_ftp, ip_conntrack_irc, iptable_nat, ip_nat_ftp, ---------------------------------------------------------------------- Done loading modules. Enabling forwarding.. Clearing any existing rules and setting default policy.. External IP detected as 10.150.47.24 Closing all external ports but allowing ICMP... - TCP 22 reopened Allowing existing and related connections to local servives, rejecting all other non-ICMP traffic Ikari found in /etc/hosts Forwarding incoming connections to Ikari (192.168.0.4) by port... - TCP 80 - TCP 26346 - TCP 113 - TCP 4899 - TCP 1024 - TCP 5190 - UDP 26346 Using NetBIOS to ask for Kirara Forwarding incoming connections to Kirara (192.168.0.12) by port... - TCP 5443 - TCP 2902 - TCP 56881 - UDP 2902 - UDP 56881 Using NetBIOS to ask for Mum Unable to obtain valid IP address, skipping Mum FWD: Allow all connections OUT and only existing and related ones IN Enabling SNAT (MASQUERADE) functionality on eth0 rc.firewall-iptables v0.78 done.
Notice that it skips “Mum” as it (the computer) is not on at the moment.
In case you're thinking “External IP of 10.x.x.x??”, you're quite right. But that's the IP my ADSL provider gives me, so for all intents and purposes, it's my external IP, even if it isn't what the rest of the net sees.
==
«< Request for Feedback ::: Feel free to contact me about this script, or anything else mentioned/implied by this page. »>
<hostname>
text is literal, it seems that dhclient expands this at the right time somehow