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
"[email protected]" * "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 [email protected] USER='[email protected]'
# 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)
|