PPPoE for Linux
Many Internet service providers are using the Point-to-Point Protocol over Ethernet (PPPoE) to provide residential Digital Subscriber Link (DSL) broadband Internet access. Most ISP’s do not support Linux and supply PPPoE clients only for Windows and Mac OS.
The PPPoE Protocol
PPPoE is a protocol for encapsulating PPP frames in Ethernet frames. PPP is a data-link-level protocol typically used to encapsulate network-level packets over an asynchronous serial line. This mode of usage is called asynchronous.
While PPP is a peer-to-peer protocol, PPPoE is initially a client-server protocol. The client (usually a personal computer) searches for a PPPoE server (called an access concentrator) and obtains the access concentrator’s MAC address and a session number. The process of setting up a PPPoE session is called discovery.
The Pseudo-TTY
The pppd program and the Linux kernel expect to transmit PPP frames over a TTY device. Luckily, UNIX (and Linux) support the concept of a pseudo-tty. This is a device which “looks” like a TTY, but instead of being connected to a physical terminal, it is connected to a UNIX process. Whenever something writes to the pseudo-tty, the data appears on the standard input of the back-end process. Whenever the back-end process writes to its standard output, the data may be read from the pseudo-tty.Even more luckily, recent versions of pppd (2.3.7 and newer) support a pty option. This option automatically starts the back-end process and performs all the mundane operations required to connect it to a pseudo-tty. So to start the PPPoE link, you start pppd with the appropriate
pty option, which runs the pppoe executable connected to the pseudo-tty.
The MTU Problem
PPPoE introduces a real and annoying problem. The maximum Ethernet frame is 1518 bytes long. 14 bytes are consumed by the header, and 4 by the frame-check sequence, leaving 1500 bytes for the payload. For this reason, the Maximum Transmission Unit (MTU) of an Ethernet interface is usually 1500 bytes.This is the largest IP datagram which can be transmitted over the interface without fragmentation. PPPoE adds another six bytes of overhead, and the PPP protocol field consumes two bytes, leaving 1492 bytes for the IP datagram. The MTU of PPPoE interfaces is therefore 1492 bytes.When a TCP connection is initiated, each side can optionally specify the Maximum Segment Size (MSS). TCP chops a stream of data into segments, and MSS specifies the largest segment each side will accept. By default, the MSS is chosen as the MTU of the outgoing interface minus the usual size of the TCP and IP headers (40 bytes), which results in an MSS of 1460 bytes for an Ethernet interface.TCP stacks try to avoid fragmentation, so they use an MSS which will not cause fragmentation on their outgoing interface. Unfortunately, there may be intermediate links with lower MTU’s which will cause fragmentation. Good TCP stacks perform path MTU discovery. In path MTU discovery, a TCP stack sets a special Don’t Fragment (DF) bit in the IP datagrams. Routers which cannot forward the datagram without fragmenting it are supposed to drop it and send an ICMP “Fragmentation-Required” datagram to the originating host.The originating host then tries a lower MTU value. Unfortunately, many routers are anti-social and do not generate the fragmentation-required datagrams. Many firewalls are equally anti-social and drop all ICMP datagrams.Now consider a client workstation on an Ethernet LAN connected to a PPPoE gateway. It opens a TCP connection to a web server. Because the Ethernet MTU is 1500, it suggests an MSS of 1460. The web server is also on an Ethernet and also suggests an MSS of 1460. The client then requests a web page. This request is typically small and reaches the web server. The server responds with many TCP segments, most of which are 1460 bytes long.The maximum-sized segments result in 1500-byte IP datagrams and make their way to the DSL provider. The DSL provider cannot transmit a 1500-byte IP datagram over a PPPoE link, so it drops it (assume for now that the DF bit is set.) Furthermore, being anti-social, the DSL provider does not send an ICMP message to the web server.The net result is that packets are silently dropped. The web client hangs waiting for data, and the web server keeps retransmitting until it finally gives up, or the connection is closed by the user aborting the web client.One way around this is to artificially set an MSS for the default route on all LAN hosts behind the PPPoE gateway. This is annoying, as it requires changes on each host. Instead, rp-pppoe “listens in” on the MSS negotiation and modifies the MSS if it is too big. Adjusting the MSS is a hack. It breaks the concept of the transport-layer being end-to-end. It will not work with IPSec, because IPSec will not let you damage IP packets (they will fail to authenticate.) Nevertheless, it is a fairly effective solution to an ugly real-world problem, and is used by default in rp-pppoe.
Installation and Configuration of PPP / PPPoE
We setup a GENTOO 2005.0 Linux machine with RP-PPPoE, PPP and the Firewall Software iptables. The internal network 192.168.138.0 is mapped to the dynamically asigned IP address using NAT / IP-Masquerading.
Download RP-PPPoE from RoaringPenguin
tar xzvf rp-pppoe-xxx.tar.gz
cd src
./configure
make
make install
cd /etc/ppp
ls -l-rw------- 1 root root 37 Jul 25 09:59 chap-secrets
-rw------- 1 root root 0 Jul 25 09:59 chap-secrets-bak
-rw------- 1 root root 78 Jul 25 09:42 chap-secrets.example
-rw-r--r-- 1 root root 353 Jul 25 09:42 chat-default
-rw-r--r-- 1 root root 938 Jul 25 09:53 firewall-masq
-rw-r--r-- 1 root root 836 Jul 25 09:53 firewall-standalone
-rwxr-xr-x 1 root root 931 Jul 25 09:42 ip-down*
-rwxr-xr-x 1 root root 1081 Jul 25 09:42 ip-up*
-rw-r--r-- 1 root root 5 Jul 25 09:42 options
-rw-r--r-- 1 root root 53 Jul 25 09:42 options-pppoe
-rw-r--r-- 1 root root 238 Jul 25 09:42 options-pptp
-rw------- 1 root root 37 Jul 25 09:59 pap-secrets
-rw------- 1 root root 0 Jul 25 09:59 pap-secrets-bak
-rw------- 1 root root 77 Jul 25 09:42 pap-secrets.example
drwxr-xr-x 2 root root 4096 Jul 25 09:42 peers/
drwxr-xr-x 2 root root 4096 Jul 25 09:53 plugins/
-rw-r--r-- 1 root root 4592 Jul 25 09:59 pppoe.conf
-rw------- 1 root root 4562 Jul 25 09:59 pppoe.conf-bak
-rw-r--r-- 1 root root 104 Jul 25 09:53 pppoe-server-options
How to Connect
Set up your Ethernet hardware
First, make sure the Ethernet card you intend to use with the modem is visible to the Linux kernel.
ifconfig eth0
should display something like this:
eth0 Link encap:Ethernet HWaddr 00:60:67:62:31:D4
plust some more lines. Your HWaddr will be different. DO NOT assign an IP address to the Ethernet card. DO NOT configure the card to come up at boot time. Note, that the PPP-Interface (ppp0) is automatically setup by PPPoE/PPP, it cannot be setup manually.
Configure various files
Several files need editing. The easiest way to do this is to run the following command as root:
adsl-setup
Answer the questions and you should be all set. If you want to know what goes on behind, continue reading.
Edit pap-secrets
"xx.xyz@domain.ch" * "xxxxxxx"
Edit the "pap-secrets" file, inserting your proper user-ID and password. Install the file (or copy the relevant lines) to /etc/ppp/pap-secrets. Your ISP may use CHAP authentication. In this case, add the line to /etc/ppp/chap-secrets.
Edit pppoe.conf
The file /etc/ppp/pppoe.conf contains configuration information for the ADSL connection.
#***********************************************************************
#
# pppoe.conf
#
# Configuration file for rp-pppoe. Edit as appropriate and install in
# /etc/ppp/pppoe.conf
#
# NOTE: This file is used by the adsl-start, adsl-stop, adsl-connect and
# adsl-status shell scripts. It is *not* used in any way by the
# "pppoe" executable.
#
# Copyright (C) 2000 Roaring Penguin Software Inc.
#
# This file may be distributed under the terms of the GNU General
# Public License.
#
# LIC: GPL
# $Id: pppoe.conf,v 1.10 2002/04/09 17:28:38 dfs Exp $
#***********************************************************************
# When you configure a variable, DO NOT leave spaces around the "=" sign.
# Ethernet card connected to ADSL modemETH='eth0'
# ADSL user name. You may have to supply "@provider.com" Sympatico
# users in Canada do need to include "@sympatico.ca"
# Sympatico uses PAP authentication. Make sure /etc/ppp/pap-secrets
# contains the right username/password combination.
# For Magma, use xxyyzz@magma.ca
USER='xx.xyz@domain.ch'
# Bring link up on demand? Default is to leave link up all the time.
# If you want the link to come up on demand, set DEMAND to a number indicating
# the idle time after which the link is brought down.
DEMAND=no
#DEMAND=300
# DNS type: SERVER=obtain from server; SPECIFY=use DNS1 and DNS2;
# NOCHANGE=do not adjust.
DNSTYPE=SPECIFY
# Obtain DNS server addresses from the peer (recent versions of pppd only)
# In old config files, this used to be called USEPEERDNS. Changed to
# PEERDNS for better Red Hat compatibility
PEERDNS=no
DNS1=195.186.4.111
DNS2=195.186.1.111
# Make the PPPoE connection your default route. Set to
# DEFAULTROUTE=no if you don't want this.
DEFAULTROUTE=yes
### ONLY TOUCH THE FOLLOWING SETTINGS IF YOU'RE AN EXPERT
# How long adsl-start waits for a new PPP interface to appear before
# concluding something went wrong. If you use 0, then adsl-start
# exits immediately with a successful status and does not wait for the
# link to come up. Time is in seconds.
#
# WARNING WARNING WARNING:
#
# If you are using rp-pppoe on a physically-inaccessible host, set
# CONNECT_TIMEOUT to 0. This makes SURE that the machine keeps trying
# to connect forever after adsl-start is called. Otherwise, it will
# give out after CONNECT_TIMEOUT seconds and will not attempt to
# connect again, making it impossible to reach.
CONNECT_TIMEOUT=30
# How often in seconds adsl-start polls to check if link is up
CONNECT_POLL=2
# Specific desired AC Name
ACNAME=
# Specific desired service name
SERVICENAME=
# Character to echo at each poll. Use PING="" if you don't want
# anything echoed
PING="."
# File where the adsl-connect script writes its process-ID.
# Three files are actually used:
# $PIDFILE contains PID of adsl-connect script
# $PIDFILE.pppoe contains PID of pppoe process
# $PIDFILE.pppd contains PID of pppd process
CF_BASE=`basename $CONFIG`
PIDFILE="/var/run/$CF_BASE-adsl.pid"
# Do you want to use synchronous PPP? "yes" or "no". "yes" is much
# easier on CPU usage, but may not work for you. It is safer to use
# "no", but you may want to experiment with "yes". "yes" is generally
# safe on Linux machines with the n_hdlc line discipline; unsafe on others.
SYNCHRONOUS=no
# Do you want to clamp the MSS? Here's how to decide:
# - If you have only a SINGLE computer connected to the ADSL modem, choose
# "no".
# - If you have a computer acting as a gateway for a LAN, choose "1412".
# The setting of 1412 is safe for either setup, but uses slightly more
# CPU power.CLAMPMSS=1412
#CLAMPMSS=no
# LCP echo interval and failure count.
LCP_INTERVAL=20
LCP_FAILURE=3
# PPPOE_TIMEOUT should be about 4*LCP_INTERVAL
PPPOE_TIMEOUT=80
# Firewalling: One of NONE, STANDALONE or MASQUERADE
FIREWALL=NONE
# Linux kernel-mode plugin for pppd. If you want to try the kernel-mode
# plugin, use LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
LINUX_PLUGIN=
# Any extra arguments to pass to pppoe. Normally, use a blank string
# like this:
PPPOE_EXTRA=""
# Rumour has it that "Citizen's Communications" with a 3Com
# HomeConnect ADSL Modem DualLink requires these extra options:
# PPPOE_EXTRA="-f 3c12:3c13 -S ISP"
# Any extra arguments to pass to pppd. Normally, use a blank string
# like this:PPPD_EXTRA=""
########## DON'T CHANGE BELOW UNLESS YOU KNOW WHAT YOU ARE DOING
# If you wish to COMPLETELY overrride the pppd invocation:
# Example:
# OVERRIDE_PPPD_COMMAND="pppd call dsl"
# If you want adsl-connect to exit when connection drops:
# RETRY_ON_FAILURE=no
Set up DNS
If you are using DNS servers supplied by your ISP, edit the file /etc/resolv.conf
Bring up the connection at boot time (For GENTOO)
#!/sbin/runscript
depend() {
need net
use logger dns
}
# Paths to programs
START=/usr/sbin/adsl-start
STOP=/usr/sbin/adsl-stop
STATUS=/usr/sbin/adsl-status
start() {
ebegin "Bringing up ADSL link"
$START &>/dev/null
touch /var/lock/subsys/adsl
eend $?
}
stop() {
ebegin "Shutting down ADSL link"
$STOP &>/dev/null
rm -f /var/lock/subsys/adsl
eend $?
}
Commands to control the ADSL linkAs root, bring up the link by typing: adsl-start
As root, bring down the link by typing: adsl-stopps -ef
/usr/sbin/adsl-connect
/usr/sbin/pppd pty /usr/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe \
-I eth0 -T 80 -U -m 1412 noipdefa
/usr/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe \
-I eth0 -T 80 -U -m 1412ifconfig -a
eth0 Link encap:Ethernet HWaddr 00:30:48:28:AA:4A
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:23529 errors:0 dropped:0 overruns:0 frame:0
TX packets:18759 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:22942360 (21.8 Mb) TX bytes:1973186 (1.8 Mb)
Base address:0x3000 Memory:fc200000-fc220000
eth1 Link encap:Ethernet HWaddr 00:30:48:28:AA:4B
inet addr:192.168.138.1 Bcast:192.168.138.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18130 errors:0 dropped:0 overruns:0 frame:0
TX packets:25373 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1819853 (1.7 Mb) TX bytes:21836499 (20.8 Mb)
Base address:0x3040 Memory:fc220000-fc240000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1590 (1.5 Kb) TX bytes:1590 (1.5 Kb)
ppp0 Link encap:Point-to-Point Protocol
inet addr:213.3.5.17 P-t-P:195.186.253.131 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:21685 errors:0 dropped:0 overruns:0 frame:0
TX packets:14272 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:22260398 (21.2 Mb) TX bytes:1314858 (1.2 Mb)netstat -nr
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
195.186.253.131 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0
192.168.138.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
127.0.0.0 127.0.0.1 255.0.0.0 UG 0 0 0 lo
0.0.0.0 195.186.253.131 0.0.0.0 UG 0 0 0 ppp0adsl-statusadsl-status: Link is up and running on interface ppp0
ppp0 Link encap:Point-to-Point Protocol
inet addr:213.3.5.17 P-t-P:195.186.253.131 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1
RX packets:2432 errors:0 dropped:0 overruns:0 frame:0
TX packets:2145 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:628102 (613.3 Kb) TX bytes:241917 (236.2 Kb)
Using A Zyxel Router as a Modem (Bridged Mode)
Connect to your Zyxel Router using TELNET. In Menu 1, change Route IP = No, Bridge = Yes.In Menu 4, change Encapsulation to RFC 1483. Make sure VPI and VCI are setup correct for your Provider.In Menu 11.2, change Route = None, Bridge = Yes.Now, reboot the Modem ... it's now a Modem no more a Router. All settings are ignored, the Modem can no longer talk PPPoE!
Linux Routing
The first task to undertake when configuring the firewall ruleset is to turn on all the options you would like the kernel to use when processing IP packets. The very first thing is that you turn ip_forwarding off - it will be turned on after everything is done. We have set the following kernel options in the /etc/conf.d/local.start.# /etc/conf.d/local.start:
# Setup Kernel Options for iptables/Firewall"
# If your firewall has a dynamic IP address, use this setting
echo 2 > /proc/sys/net/ipv4/ip_dynaddr
# Hardening settings:
if [ -e /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
for f in /proc/sys/net/ipv4/conf/*/accept_source_route
do
echo 0 > $f
done
fi
# Do not respond to 'redirected' packets
if [ -e /proc/sys/net/ipv4/conf/all/send_redirects ]; then
for f in /proc/sys/net/ipv4/conf/*/send_redirects
do
echo 0 > $f
done
fi
# Do not reply to 'proxyarp' packets
if [ -e /proc/sys/net/ipv4/conf/all/proxy_arp ]; then
for f in /proc/sys/net/ipv4/conf/*/proxy_arp
do
echo 0 > $f
done
fi
# Detecting and stopping spoofed packets
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]; then
for f in /proc/sys/net/ipv4/conf/*/rp_filter
do
echo 1 > $f
done
fi
# Ignore source routing (dictating what route the traffic will take)
# from the origin of the packet as dictated by the client
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
if [ -e /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
for f in /proc/sys/net/ipv4/conf/*/accept_source_route
do
echo 0 > $f
done
fi
# Suppress ICMP redirects
if [ -e /proc/sys/net/ipv4/conf/all/accept_redirects ]; then
for f in /proc/sys/net/ipv4/conf/*/accept_redirects
do
echo 0 > $f
done
fi
if [ -e /proc/sys/net/ipv4/conf/all/send_redirects ]; then
for f in /proc/sys/net/ipv4/conf/*/send_redirects
do
echo 0 > $f
done
fi
if [ -e /proc/sys/net/ipv4/conf/all/secure_redirects ]; then
for f in /proc/sys/net/ipv4/conf/*/secure_redirects
do
echo 0 > $f
done
fi
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
echo 1 > /proc/sys/net/ipv4/ip_forward
NAT (Network Address Translation)
Normally, packets on a network travel from their source to their destination through many different links. None of these links really alter your packet: they just send it onward.If one of these links were to do NAT, then they would alter the source or destinations of the packet as it passes through. As you can imagine, this is not how the system was designed to work, and hence NAT is always something of a crock. Usually the link doing NAT will remember how it mangled a packet, and when a reply packet passes through the other way, it will do the reverse mangling on that reply packet, so everything works.
Why Would I Want To Do NAT?
In a perfect world, you wouldn't. Meanwhile, the main reasons are:
- Modem Connections To The Internet
Most ISPs give you a single IP address when you dial up to them. You can send out packets with any source address you want, but only replies to packets with this source IP address will return to you. If you want to use multiple different machines (such as a home network) to connect to the Internet through this one link, you'll need NAT.This is by far the most common use of NAT today, commonly known as «masquerading» in the Linux world. I call this SNAT, because you change the source address of the first packet.
- Multiple Servers
Sometimes you want to change where packets heading into your network will go. Frequently this is because (as above), you have only one IP address, but you want people to be able to get into the boxes behind the one with the real IP address. If you rewrite the destination of incoming packets, you can manage this. This type of NAT was called port-forwarding under previous versions of Linux.
- Transparent Proxying
Sometimes you want to pretend that each packet which passes through your Linux box is destined for a program on the Linux box itself. This is used to make transparent proxies: a proxy is a program which stands between your network and the outside world, shuffling communication between the two. The transparent part is because your network won't even know it's talking to a proxy, unless of course, the proxy doesn't work. Squid can be configured to work this way, and it is called redirection or transparent proxying under previous Linux versions.
The Two Types of NAT
NAT is divided into two different types: Source NAT (SNAT) and Destination NAT (DNAT).
- SNAT
Source NAT is when you alter the source address of the first packet: i.e. you are changing where the connection is coming from. Source NAT is always done post-routing, just before the packet goes out onto the wire. Masquerading is a specialized form of SNAT.
- DNAT
Destination NAT is when you alter the destination address of the first packet: i.e. you are changing where the connection is going to. Destination NAT is always done before routing, when the packet first comes off the wire. Port forwarding, load sharing, and transparent proxying are all forms of DNAT.
Examples
Here are our NAT rules as examples.# echo "Static NAT: Masquerade our Traffic"
# $IPTABLES -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
echo "Static NAT to IP: 213.3.5.17"
$IPTABLES -t nat -A POSTROUTING -o ppp0 -j SNAT --to 213.3.5.17
echo "DNAT Portforwarding: 25 --> 192.168.138.28:25"
$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 25 -j DNAT --to 192.168.138.28:25
echo "DNAT Portforwarding: 53 --> 192.168.138.20:25"
$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 53 -j DNAT --to 192.168.138.20:53
$IPTABLES -t nat -A PREROUTING -p udp -i ppp0 --dport 53 -j DNAT --to 192.168.138.20:53
echo "DNAT Portforwarding: 80 --> 192.168.138.21:80"
$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 80 -j DNAT --to 192.168.138.21:80
Firewall with netfilter/iptables
netfilter and iptables are building blocks of a framework inside the Linux 2.4.x and 2.6.x kernel. This framework enables packet filtering, network address translation and other packet mangling. It is the re-designed and heavily improved successor of the previous Linux 2.2.x ipchains and Linux 2.0.x ipfwadm systems.netfilter is a set of hooks inside the Linux kernel that allows kernel modules to register callback functions with the network stack. A registered callback function is then called back for every packet that traverses the respective hook within the network stack.iptables is a generic table structure for the definition of rulesets. Each rule within an IP table consists of a number of classifiers (iptables matches) and one connected action (iptables target).Main Features
- stateless packet filtering (IPv4 and IPv6)
- stateful packet filtering (IPv4)
- all kinds of network address and port translation (NAT/NAPT)
- flexible and extensible infrastructure
- multiple layers of API's for 3rd party extensions
- large number of plugins/modules kept in 'patch-o-matic' repository
What can I do with netfilter/iptables?
- build internet firewalls based on stateless and stateful packet filtering
- use NAT and masquerading for sharing internet access if you don't have enough public IP addresses
- use NAT to implement transparent proxies
- aid the tc and iproute2 systems used to build sophisticated QoS and policy routers
- do further packet manipulation (mangling) like altering the TOS/DSCP/ECN bits of the IP header
An iptable tutortial can be found here.
Stateful Inspection and Connection Tracking
Stateful packet inspection uses the same fundamental packet screening technique that packet filtering does. In addition, it examines the packet header information from the network layer of the OSI model to the application layer to verify that the packet is part of a legitimate connection and the protocols are behaving as expected.The stateful packet inspection process is accomplished in the following manner. As packets pass through the firewall, packet header information is examined and fed into a dynamic state table where it is stored. The packets are compared to pre-configured rules or filters and allow or deny decisions are made based on the results of the comparison. The data in the state table is then used to evaluate subsequent packets to verify that they are part of the same connection. In short, stateful packet inspection uses a two step process to determine whether or not packets will be allowed or denied. This method can make decisions based on one or more of the following:
- Source IP address
- Destination IP address
- Protocol type (TCP/UDP)
- Source port
- Destination port
- Connection state
The connection state is derived from information gathered in previous packets. It is an essential factor in making the decision for new communication attempts. Stateful packet inspection compares the packets against the rules or filters and then checks the dynamic state table to verify that the packets are part of a valid, established connection. By having the ability to "remember" the status of a connection, this method of packet screening is better equipped to guard against attacks than standard packet filtering.Stateful packet inspection solutions offer sophisticated decision-making capabilities, yet they operate faster than other packet screening methods because they require little processing overhead. Allow and deny decisions are made at the lower levels of the OSI model.Some newer stateful packet inspection firewalls maintain more advanced connection state information. Some are able to reassemble the packets as they pass through the firewall and perform additional processing such as content filtering.
Connection States
- NEW
This packet is trying to create a new connection. Unless you're running a server you shouldn't allow these on the input side.
- RELATED
This packet is related to the existing connection, and is passing in the original direction.
- INVALID
his packet doesn't match any connection
- ESTABLISHED
This packet is part of an existing connectionAs a simple example, to forward across the firewall interfaces packets that are part of a pre-existing connection might look like this:iptables -A FORWARD -m state -state ESTABLISHED,RELATED -j ACCEPT
Installation and Configuration
Download iptables from netfilter.org, on GENTOO use
emerge iptables
- Prepare the Kernel
cd /usr/src/linux
make menuconfig(Enable Network packet filtering in Networking options)
- Download Firewall Builder from fwbuilder.org
With this tool, you can build the basic iptables rules. Here are our basic rules.
#!/bin/sh
# Akadia AG, Fichtenweg 10, 3672 Oberdiessbach
# --------------------------------------------------------------------------
# File: firewall.fw
#
# Autor: Martin Zahn, 28.07.2005
#
# Purpose: Configuration file IPTABLES Firewall
#
# Location: /home/zahn/iptables
#
# Load Rules: ./firewall.fw
# Save Rules: /etc/init.d/iptables save
#
# --------------------------------------------------------------------------
#
PATH="/sbin:/usr/sbin:/bin:/usr/bin:${PATH}"
export PATH
log() {
echo "$1"
test -x "$LOGGER" && $LOGGER -p info "$1"
}
va_num=1
add_addr() {
addr=$1
nm=$2
dev=$3
type=""
aadd=""
L=`$IP -4 link ls $dev | head -n1`
if test -n "$L"; then
OIFS=$IFS
IFS=" /:,<"
set $L
type=$4
IFS=$OIFS
L=`$IP -4 addr ls $dev to $addr | grep inet | grep -v :`
if test -n "$L"; then
OIFS=$IFS
IFS=" /"
set $L
aadd=$2
IFS=$OIFS
fi
fi
if test -z "$aadd"; then
if test "$type" = "POINTOPOINT"; then
$IP -4 addr add $addr dev $dev scope global label $dev:FWB${va_num}
va_num=`expr $va_num + 1`
fi
if test "$type" = "BROADCAST"; then
$IP -4 addr add $addr/$nm dev $dev brd + scope global label $dev:FWB${va_num}
va_num=`expr $va_num + 1`
fi
fi
}
getInterfaceVarName() {
echo $1 | sed 's/\./_/'
}
getaddr() {
dev=$1
name=$2
L=`$IP -4 addr show dev $dev | grep inet | grep -v :`
test -z "$L" && {
eval "$name=''"
return
}
OIFS=$IFS
IFS=" /"
set $L
eval "$name=$2"
IFS=$OIFS
}
getinterfaces() {
NAME=$1
$IP link show | grep ": $NAME" | while read L; do
OIFS=$IFS
IFS=" :"
set $L
IFS=$OIFS
echo $2
done
}
LSMOD="lsmod"
MODPROBE="modprobe"
IPTABLES="iptables"
IPTABLES_RESTORE="iptables-restore"
IP="ip"
LOGGER="logger"
getaddr ppp0 i_ppp0
log 'Activating firewall script'
echo "Cleanup iptables Rules"
$IPTABLES -P OUTPUT DROP
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
# $IPTABLES -F
# $IPTABLES -X
cat /proc/net/ip_tables_names | while read table; do
test "X$table" = "Xmangle" && continue
$IPTABLES -t $table -L -n | while read c chain rest; do
if test "X$c" = "XChain" ; then
$IPTABLES -t $table -F $chain
fi
done
$IPTABLES -t $table -X
done
# echo "Mainly for PPPoE, VPN and DSL (MTU Fix, activate it if you have)"
# echo "Problems with large Downloads over PPPoE"
# $IPTABLES -A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
# $IPTABLES -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
#
echo "Connection Tracking Rules"$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT#
# echo "NAT: Masquerade our Traffic"
# $IPTABLES -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
echo "Static NAT to IP: 213.3.5.17"
$IPTABLES -t nat -A POSTROUTING -o ppp0 -j SNAT --to 213.3.5.17
# echo "Portforwarding: 25 --> 192.168.138.28:25"$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 25 -j DNAT --to 192.168.138.28:25
# echo "Portforwarding: 53 --> 192.168.138.28:25"$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 53 -j DNAT --to 192.168.138.28:53
$IPTABLES -t nat -A PREROUTING -p udp -i ppp0 --dport 53 -j DNAT --to 192.168.138.28:53
# echo "Portforwarding: 80,8080,8081 --> 192.168.138.28:80,8080,8081"$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 80 -j DNAT --to 192.168.138.28:80
$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 8080 -j DNAT --to 192.168.138.28:8080
$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 8081 -j DNAT --to 192.168.138.28:8081
# echo "Portforwarding: 143 --> 192.168.138.28:143"$IPTABLES -t nat -A PREROUTING -p tcp -i ppp0 --dport 143 -j DNAT --to 192.168.138.28:143#echo "Anti Spoofing Rule"
$IPTABLES -N ppp0_In_RULE_0
test -n "$i_ppp0" && $IPTABLES -A INPUT -i ppp0 -s $i_ppp0 -j ppp0_In_RULE_0
$IPTABLES -A INPUT -i ppp0 -s 192.168.138.1 -j ppp0_In_RULE_0
$IPTABLES -A INPUT -i ppp0 -s 192.168.138.0/24 -j ppp0_In_RULE_0
test -n "$i_ppp0" && $IPTABLES -A FORWARD -i ppp0 -s $i_ppp0 -j ppp0_In_RULE_0
$IPTABLES -A FORWARD -i ppp0 -s 192.168.138.1 -j ppp0_In_RULE_0
$IPTABLES -A FORWARD -i ppp0 -s 192.168.138.0/24 -j ppp0_In_RULE_0
$IPTABLES -A ppp0_In_RULE_0 -j LOG --log-level info --log-prefix "RULE 0 -- DENY "
$IPTABLES -A ppp0_In_RULE_0 -j DROP
#echo "Loopback (lo) Rules"
$IPTABLES -A INPUT -i lo -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -o lo -m state --state NEW -j ACCEPT
#
echo "Allow the following TCP Ports from Aynwhere"
$IPTABLES -A OUTPUT -p tcp -m tcp -m multiport --dports 22,80,443,25,143,8080,8081 \
-m state --state NEW -j ACCEPT
$IPTABLES -A INPUT -p tcp -m tcp -m multiport --dports 22,80,443,25,143,8080,8081 \
-m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -p tcp -m tcp -m multiport --dports 22,80,443,25,143,8080,8081 \
-m state --state NEW -j ACCEPT
#
echo "Allow DNS Zone Transfer only from 62.2.210.211"
$IPTABLES -A OUTPUT -p tcp -m tcp -d 62.2.210.211 --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A INPUT -p tcp -m tcp -d 62.2.210.211 --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -p tcp -m tcp -d 62.2.210.211 --dport 53 -m state --state NEW -j ACCEPT#
echo "Allow DNS Queries"$IPTABLES -A OUTPUT -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A INPUT -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT
#
echo "Allow NTP Time to setup the Date/Time from NTP Server"$IPTABLES -A OUTPUT -p udp -m udp --dport 123 -m state --state NEW -j ACCEPT
$IPTABLES -A INPUT -p udp -m udp --dport 123 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -p udp -m udp --dport 123 -m state --state NEW -j ACCEPT
#
echo "HSZ Rules"
$IPTABLES -A INPUT -s 192.168.138.0/24 -m state --state NEW -j ACCEPT
$IPTABLES -A OUTPUT -s 192.168.138.0/24 -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -s 192.168.138.0/24 -m state --state NEW -j ACCEPT
#
echo "Logging Rules"$IPTABLES -N RULE_2
$IPTABLES -A OUTPUT -j RULE_2
$IPTABLES -A INPUT -j RULE_2
$IPTABLES -A FORWARD -j RULE_2
$IPTABLES -A RULE_2 -j LOG --log-level info --log-prefix "RULE 2 -- DENY "
$IPTABLES -A RULE_2 -j DROP#
echo "Activate Routing"
echo 1 > /proc/sys/net/ipv4/ip_forward
- Load and Save the Rules
./firewall.fw
/etc/init.d/iptables save
The iptables rules are saved and automatically loaded when the machine is booting the next time. The location of the saved rules are defined in/etc/conf.d/iptables (/var/lib/iptables/rules-save) for GENTOO linux.
Useful iptables Commands
iptables -L (List Rules)
iptables -t nat -L (List NAT Rules)
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- anywhere anywhere tcp dpt:smtp to:192.168.138.28:25
DNAT tcp -- anywhere anywhere tcp dpt:domain to:192.168.138.20:53
DNAT udp -- anywhere anywhere udp dpt:domain to:192.168.138.20:53
DNAT tcp -- anywhere anywhere tcp dpt:www to:192.168.138.21:80
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- anywhere anywhere to:213.3.5.17
Chain OUTPUT (policy ACCEPT)
target prot opt source destinationiptables -F (Delete all rules)
iptables -X (Delete all userdefined chains)
Source: www.akadia.com.