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 PPP from Sambas Site, on GENTOO Linux use:
emerge ppp
This creates the directory/etc/ppp
-
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 modem ETH='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 link
As root, bring up the link by typing:
adsl-start
As root, bring down the link by typing: adsl-stop
ps -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 1412
ifconfig -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 ppp0
adsl-status
adsl-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.
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.
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).
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.
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.
- 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 connection
As 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
destination
iptables -F (Delete all rules)
iptables -X (Delete all userdefined chains)
|