1 Introduction
1.1 Why?
1.2 How?
1.3 Who are you?
2 Preparations
2.1 Where to get?
2.2 Kernel setup
2.2.1 Explanations of used options
2.2.2 userland setup
3 rc.firewall file
3.1 example rc.firewall
3.2 explanation of rc.firewall
3.2.1 Initial loading of extra modules
3.2.2 Initiating the kernel for IP forwarding and others
3.2.3 Actually starting the MASQUERADING
3.2.4 Displacement of rules to different chains, why?
3.2.5 Setting up the different chains used
3.2.6 The TCP allowed chain, last check before allowing TCP
3.2.7 ICMP chain
3.2.8 TCP chain
3.2.9 UDP chains
3.2.10 PREROUTING chain of the NAT table
3.2.11 INPUT chain
3.2.12 OUTPUT chain
3.2.13 FORWARD chain
4 Appendix
4.1 Passive FTP but no DCC, extra read for the interested
4.2 Weird ISP's who use assigned IP's
4.3 Updating and flushing your tables
4.4 Other resources and links
5 Contributers
1 Introduction
1.1 Why?
Well, I found all the HOWTO's out there lacking in information about
the new iptables functions in the new linux 2.4.x kernels, among other
things, I'm going to try to answer questions that some might have about
the new possibilities like state matching, is it possible to only allow
passive FTP's to your server, but not allow outgoing DCC's from IRC as an
example? I will build this all up from an example rc.firewall file that you can use in your
/etc/rc.d/ scripts. Yes, this file was originally from the masquerading
HOWTO for those of you that recognizes it.
Also, there's a small script that I wrote just in case you screw up as
much as I did during the configuration available as flush-iptables.txt.
1.2 How?
Well, I've placed questions to Marc Boucher and others from the core
netfilter team. A big thanks going out to them for their work and for
their help on this tutorial I'm writing for boingworld.com. This document
will guide you through the setup process step by step, hopefully make you
understand some more about the iptables package. I will base most of the
stuff her on the example rc.firewall file since I find that to be a good
way to learn how to use iptables. I'm a bit uncertain on how i should
structure this text, but I finally decided to just follow the rc.firewall
file from the top to the bottom, in other words, you can read the
rc.firewall file and when you hit something you don't understand you
consult this file.
1.3 Who are you?
I'm someone with to many old computers on my hands sitting in my own LAN
and wanting them all to be connected to the Internet, at the same time
having it fairly secure. The new iptables is a damn good upgrade
from the old ipchains in this regard, before, you could make a fairly
secure network by dropping all incoming packages not destined to certain
ports, but this would be a problem with things like passive FTP or
outgoing DCC's in IRC, which assigns ports on the server, tells the client
about it, and then lets the client connect. Though, there is still some
childs diseases in the new iptables code that I've ran into so far, and in
some respects i find the code still not quite ready for release in full
production, but I'd pretty much recommend everyone who uses ipchains or
even older ipfwadm etc to upgrade unless they're happy with what their
current code is capable of and if it does what they need it to.
2 Preparations
2.1 Where to get?
The iptables user space package can be downloaded from
http://netfilter.filewatcher.org.
The iptables package also makes use of kernel space facilities which can
be configured into the kernel during make configure, the necessary pieces
will be discussed a bit further down in this document.
2.2 Kernel setup
To run the pure basics of you need to configure in the following options
into the kernel:
CONFIG_PACKET
CONFIG_NETFILTER
And of course you need to configure your proper interfaces so they work,
ie. Ethernet, PPP and slip interfaces.
If you want to use the more advanced options, you need to set those in
your kernel too:
CONFIG_IP_NF_CONNTRACK
CONFIG_IP_NF_FTP
CONFIG_IP_NF_IPTABLES
CONFIG_IP_NF_MATCH_LIMIT
CONFIG_IP_NF_MATCH_MAC
CONFIG_IP_NF_MATCH_MARK
CONFIG_IP_NF_MATCH_MULTIPORT
CONFIG_IP_NF_MATCH_TOS
CONFIG_IP_NF_MATCH_STATE
CONFIG_IP_NF_MATCH_UNCLEAN
CONFIG_IP_NF_MATCH_OWNER
CONFIG_IP_NF_FILTER
CONFIG_IP_NF_TARGET_REJECT
CONFIG_IP_NF_TARGET_MIRROR
CONFIG_IP_NF_NAT
CONFIG_IP_NF_NAT_NEEDED
CONFIG_IP_NF_TARGET_MASQUERADE
CONFIG_IP_NF_TARGET_REDIRECT
CONFIG_IP_NF_NAT_FTP
As you can see, there is a heap of them, and i will not go through them
all here so you'll most probably need to go through those if you have any
specific needs or are just curious. The built in help in make config and
other commands are very useful to get a basic understand of this, as well
as the HOWTO's at http://netfilter.filewatcher.org
The one's that you will need to use the features that I will talk about
will be the following:
CONFIG_PACKET
CONFIG_NETFILTER
CONFIG_IP_NF_CONNTRACK
CONFIG_IP_NF_FTP
CONFIG_IP_NF_IPTABLES
CONFIG_IP_NF_MATCH_STATE
CONFIG_IP_NF_MATCH_UNCLEAN
CONFIG_IP_NF_TARGET_REJECT
CONFIG_IP_NF_TARGET_MASQUERADE
at the very least.
2.2.1 Explanations of used options
CONFIG_PACKET will allow some programs like tcpdump to work, not really
used in this tutorial, but since you're reading this, i assume you're
interested in the security aspects as well. tcpdump and snort etc might be
a good add on aspect in this case.
CONFIG_NETFILTER enables the packet filters in the kernel, you won't be
able to use the iptables without this option set. Nor will you be able to
masquerade your connection without it.
CONFIG_IP_NF_CONNTRACK Connection tracking, this keeps track of
connections and how and where packets are related into a connection. This
is required to do masquerading or any kind of NAT!
CONFIG_IP_NF_FTP this tracks FTP connections since it's a bit problematic
to do with the basic filters, therefore it's a separate piece of
code. This is required if you want to do some kind of NAT and masquerading
on FTP connections.
CONFIG_IP_NF_IPTABLES This is the iptables support, this is required if
you want to use iptables(and i wouldn't understand why you would read
this document if you didn't want to use it).
CONFIG_IP_NF_MATCH_STATE This is the state matching code for the iptables,
this is new since 2.3.x and 2.4.x kernels, unfortunately not very well
documented so far, and this is one of the things i would like to
remedy. What it does is add the possibility to filter packets based on how
they are related to other connections, for example, you can let passive
FTP clients get through an otherwise totally closed down server of yours
and download files and list directories etc.
CONFIG_IP_NF_MATCH_UNCLEAN includes support for matching unclean packets
or invalid packets by looking at series of fields in the headers of
packets.
CONFIG_IP_NF_TARGET_REJECT This piece of code adds the REJECT target to
your filters. In other words, it will allow you to reply with an ICMP
error instead of just DROP'ing the package dead on the ground. This can be
nice sometimes, if you feel like at least giving whomever a hint that they
are unable to connect.
CONFIG_IP_NF_NAT Allows you to do masquerading, port forwarding and so
on. You will need this to allow your LAN to connect to the Internet if
you have only one assigned IP to the Internet etc and still want all your
boxes to connect to it.
CONFIG_IP_NF_TARGET_MASQUERADE makes it possible to change all outgoing
connections from your LAN to the Internet(for example) so they seem to
come from another host than the normal box IP. For more information on how
this works in theory check out the masquerading HOWTO.
Of course you might not want to use all of these options or you might want
to use other config options at your own will, but these are the one i will
mainly focus on in this tutorial and for setting up basic security on your
box.
2.2.2 userland setup
All you need to do here is to configure and make the iptables package
available at http://netfilter.filewatcher.org
. Of course, don't forget to install the package, might be a good idea.
3 rc.firewall file
3.1 example rc.firewall
OK, so you've got everything setup and are ready to check out an example
rc.firewall file, or at least you should be. This example rc.firewall
script is separate from this tutorial, its large and lots of comments in
it so look at that and then come back here for more explanations.
example rc.firewall file.
3.2 explanation of rc.firewall
3.2.1 Initial loading of extra modules
First, we see to it that the module dependencies files are up to date by
issuing an /sbin/depmod -a command. After this we load some modules that
we might be interested in. For example, if you want to have support for
the LOG, REJECT and MASQUERADE targets and don't have this compiled
statically into your kernel, we load these modules.
Next is the option to load ipt_owner module, for example only allowing
certain users to make certain connections etc. I will not use that in this
example but basically, you could allow only root to do FTP and http
connections to redhat and DROP all the others. Or you could disallow all
users but your own user and root to connect from your box to the Internet,
might be boring for others, but you will be a bit more secure to bouncing
hacker attacks etc.
After this there is the first part used by our state matching filters, the
loading of ip_conntrack_ftp and ip_conntrack_irc. To do what I preached in
the beginning of this file, namely doing state matching, disallowing for
example passive FTP but allowing DCC sends to work, we load only the
ip_conntrack_ftp module, but not the ip_conntrack_irc module. For this to
work, these two must _not_ be compiled into the kernel, i repeat, must
_not_. For the vice versa, where we want passive FTP to work, but not DCC
send, we do it the other way around of course, load the IRC module, but
not the FTP module. What this does, is that it adds the ability to the
kernel to recognize for example an passive FTP connection that is related
to an currently active FTP control session, but since the IRC module is
not loaded, the kernel will not know how to recognize if it's related to
any currently active stream, and hence it will not allow these
connections. If you do it the other way around, the opposite will be in
effect.
3.2.2 Initiating the kernel for IP forwarding and others
After this we start the IP forwarding by echoing a 1 to
/proc/sys/net/ipv4/ip_forward in this fashion:
echo "1" > /proc/sys/net/ipv4/ip_forward
In case you need dynamic IP support, for example if you use SLIP, PPP or
DHCP you may enable the next option, ip_dynaddr by doing the following:
echo "1" > /proc/sys/net/ipv4/ip_dynaddr
etc, if there's any other options you might need to turn on you should
follow that style, there's other documentations on how to do these things
and this isn't either what this document is supposed to help you with.
3.2.3 Actually starting the MASQUERADING
So, our first mission would be to get the MASQUERADING up, correct? well,
at least to me. First of all we add a rule to the nat table, in the
POSTROUTING chain that will masquerade all packets going out on our
interface connected to the Internet. For me this would be eth0, -t tells
us which table to use, in this case nat, -A tells us that we want to Add
a new rule to an existing chain named POSTROUTING and -o eth0 tells us to
match all outgoing packets on eth0 and finally we target the packet for
MASQUERADE'ing. So all packets that matches this rule will be masqueraded
to look as it came from your Internet interface. Simple, isn't it?=)
The next step we take is to ACCEPT all packets traversing the FORWARD
chain in the default table 'filters' that comes from the input interface
eth1 which is my interface connecting to the internal network. All packets
that are being forwarded on our box traverses the FORWARD chain in the
filters table.
The next thing we do is to ACCEPT all packets from anywhere
that is ESTABLISHED and/or RELATED to some connection. In other words, we
first send a packet from our local box behind eth1, and since it comes
from eth1 we ACCEPT it, then when the Internet box replies, it gets
caught by this rule since the connection has seen packets in both
directions.
The last thing we do is to log all traffic that gets dropped over the
border, and hits the default policy. In some cases these might be packets
that should've gotten through but didn't, in other cases it might be
packets that definitely shouldn't get through and you want to be notified
about this. We allow this rule to be matched a maximum of 3 times per
minute with a burst limit of 3. This means we get maximally 3 log entries
per minute from this specific line, and the burst is also set to 3 so if
we get 3 log entries in 2 seconds, it'll have to wait for another 1 minute
for the next log entry. This is good if someone starts to flood you with
crap stuff that otherwise would generate many megabytes of logs. We also
set a prefix to the log with the --log-prefix and set the log level with
the --log-level. Log level tells the syslogd, or logging facility what
kind of importance this log entry has.
3.2.4 Displacement of rules to different chains, why?
I've displaced all the different chains in the fashion I've done to save
as much CPU as possible. Instead of letting a TCP packet traverse ICMP,
UDP and TCP rules, i just simply match all TCP packets and then let the
TCP packet traverse another chain. This way we don't get too much overhead
out of it all. The following picture will try and explain the basic of how
an incoming packet traverses your ipfilters. This picture was pretty much
stolen straight off from the packet-filtering-HOWTO.
First a routing decision is made, if it's destined for your host, it's
sent to INPUT, if it's destined for some box on the localnet it's sent to
FORWARD. Then they traverse whichever of those chains. When and if your
local box replies to the packets destined for the server, they will
traverse the OUTPUT chain.
Here's pictures how they would traverse the INPUT and FORWARD and OUTPUT
chains separately since the picture would be way to large if we would fit
them all together in one:
When a packet hits the INPUT chain, it will first be checked to see if
it's an ICMP packet, if it is, it's sent to icmp_packets and checked if
it's allowed or not. If it is, we just drop out of the INPUT chain and
tells it to ACCEPT the packet. If it is not, it will reach the end of the
icmp_packets chain get back to INPUT chain and reach the end with some
more checks to see if it's from localhost or localnet, if it is it will be
ACCEPT'ed. Finally we check to see if the packet somehow belongs to any
other connection by checking if they are part of an ESTABLISHED or RELATED
connection, in this case we should ACCEPT them. If it doesn't match
anything, it will finally hit the chain Policy which is set to DROP
everything that reaches it.
If the packet would instead be a TCP packet, it would not match the rule
as an ICMP packet and hence be sent to the next rule which checks for TCP
packets. Since it is an TCP packet it will match and be sent to the
tcp_packets chain. Here we will check if it's destined for one of the
ports we'd like to allow or not, if it is, we send it on to the allowed
chain to do some final checks on it. If it fails at some stage in this
check, it'll be passed down to the INPUT chain and traverse the same way
as the ICMP packet did.
UDP packets does the same basically, except that it will traverse the
udpincoming_packets chain, and if it fails to match any of the rules in
there, it will be passed down to the INPUT chain and travel the same way
as all the TCP and ICMP packets.
If the packet is destined to or from our local net they will be routed to
the FORWARD chain. If the packet comes from our LAN we will just ACCEPT
them as they are, no more, no less. If we would like to, we could only
accept SYN packets, but im skipping that as it is now. If the packets is
destined to our local net on the other hand, we only match packets in
ESTABLISHED or RELATED streams since we don't want hosts from the outside
to be able to establish new connections to our LAN. If none of these rules
are matched the packet gets DROP'ed by our chain policy.
This chain is rather straight forward. We allow everything from localhost
to go out, we allow everything from our own local network's ip to go out,
and last of all we allow everything from our own ip to go out to the
internet. You might want to just erase all this in certain cases, just
dont forget to erase the default policy of the OUTPUT chain which is set
to DROP everything.
3.2.5 Setting up the different chains used
So, now you've got a small picture how the packets traverses the different
chains and how they belong together, we'll take care of setting it all up.
First of all, we set all the default policies on the different chains with
a quite simple command.
iptables -P <chain name> <policy>
The default policy is used every time if the packets don't match a rule in
the chain. After this, we create the different special chains that we want
to use with the -N command. The new chains are created and setup with no
rules inside of them. The chains we will use is icmp_packets, tcp_packets,
udpincoming_packets and the allowed chain for tcp_packets. Incoming
packets on eth0, of ICMP type, will be redirected to the chain
icmp_packets, of TCP type, will be redirected to tcp_packets and incoming
packets of UDP type from eth0 goes to udpincoming_packets chain.
3.2.6 The TCP allowed chain, last check before allowing TCP
If a packet comes in on eth0 and is of TCP type, it travels through the
tcp_packets chain, if the connection is against an allowed port, we want
to do some final checks on it to see if we actually do want to allow it or
not.
First of all, we create the chain the same way as all the others. After
that, we check if the packet is a SYN packet. If it is a SYN packet, it is
most likely to be the first packet in a new connection so, of course, we
allow this. Then we check if the packet comes from an ESTABLISHED or
RELATED connection, if it does, then we, again of course, allow it. An
ESTABLISHED connection is a connection that has seen traffic in both
directions, and since we've got a SYN packet, and a reply to this
SYN packet, the connection then must be in state ESTABLISHED. The last
rule in this chain will DROP everything else. In this case this pretty
much means everything that hasn't seen traffic in both directions, ie, we
didn't reply to the SYN packet, or they are trying to start the connection
with a non SYN packet. There is _no_ practical use of not starting a
connection with a SYN packet, except to portscan people pretty much. There
is no currently available TCP/IP implementation that supports opening a
TCP connection with something else than a SYN packet to my knowledge,
hence, DROP the crap since it's 99% sure to be a portscan.
3.2.7 ICMP chain
This is where we decide what ICMP types to allow. If a packet of ICMP type
comes in on eth0 on the INPUT chain, we then redirect it to to the
icmp_packets chain as explained before. Here we check what kind of ICMP
types to allow. As it is now, I only allow incoming ICMP Echo Replies,
Destination unreachable, Redirect and Time Exceeded.
The reason that I allow these ICMP packets are as follows, Echo Replies is
what you get for example when you ping another host, if we don't allow
this, we will be unable to ping other hosts.
Destination Unreachable is used if a certain host is unreachable, so for
example if we send a HTTP request, and the host is unreachable, the last
gateway that was unable to find the route to the host replies with a
Destination Unreachable telling us that it was unable to find it. This way
we won't have to wait until the browsers timeouts kicks in after some 60
seconds or more.
Redirect, I allow since I might not use the best route to a host, for
example if i send a packet to Gateway 1(G1) which is on the same network
segment as Gateway 2(G2), and G1 sends the packet on to G2, G2 might tell
you to use G2 instead of G1 as to get rid of one of the hops. We might
sometimes get a faster transfer this way, not much but a little at least.
Time Exceeded, is allowed in the case where we might want to traceroute
some host or if a packet gets its Time To Live set to 0, we will get an
reply about this. For example, when you traceroute someone, you start out
with TTL = 1, and it gets down to 0 at the first hop on the way out, and a
Time Exceeded is sent back from the first gateway enroute to the host
we're trying to traceroute, then TTL = 2 and the second gateway sends Time
Exceeded, and so on until we get an actual reply from the host we finally
want to get to.
Here's a complete list of ICMP types:
Type
0 Echo Reply
3 Destination Unreachable
4 Source Quench
5 Redirect
8 Echo
11 Time Exceeded
12 Parameter Problem
13 Timestamp
14 Timestamp Reply
15 Information Request
16 Information Reply
For more information on this, i suggest reading the following sites and
reports:
http://www.ee.siue.edu/~rwalden/networking/icmp.html
ftp://sunsite.unc.edu/pub/docs/rfc/rfc792.txt
As a side-note, I might be wrong in blocking some of these things for you,
but in my case, everything's working perfectly while blocking all the
other ICMP types that I don't allow.
3.2.8 TCP chain
So, TCP connections. This specifies what ports that are allowed to use on
the firewall from the Internet. Though, there is still more checks to do,
hence we send each and one of them on to allowed chain, which we described
previously.
-A tcp_packets tells iptables in which chain to add the new rule, the rule
will be added to the end of the chain. -p TCP tells it to match TCP
packets and -s 0/0 matches all source addresses from 0.0.0.0 with netmask
0.0.0.0, in other words _all_ sources addresses, this is actually the
default behavior but I'm using it for brevity in here. --dport 21 means
destination port 21, in other words if the packet is destined for port 21
they also match. If all the criteria are matched, then the packet will
be targeted for the allowed chain. If it doesn't match any of the rules,
they will be passed back to the original chain that sent the packet to the
tcp_packets chain.
As it is now, i allow TCP port 21, or FTP control port, which is used to
control FTP connections and later on i also allow all RELATED connections,
and that way we allow PASSIVE and PORT connections since the
ip_conntrack_ftp module is, hopefully, loaded. If we just don't want to
allow FTP at all, we can unload the ip_conntrack_ftp module and delete
that line from the rc.firewall file.
Port 22 is SSH, much better than allowing telnet on port 23, if you want
to allow anyone from the outside to use a shell on your box at all.
Port 80 is HTTP, in other words your web server, delete it if you don't
want to run a web server on your site.
And finally we allow port 113, which is IDENTD and might be necessary
for some protocols like IRC, etc to work properly.
If you feel like adding more open ports with this script, well, its quite
self explanatory how to do that by now=).
3.2.9 UDP chains
When we get an UDP packet, we send them to the udpincoming_packets
from the INPUT chain.
Currently, if we do get a UDP packet on the INPUT chain, we send them on
to udpincoming_packets where we once again do a match for the UDP protocol
with -p UDP and then match everything with a source address of 0.0.0.0 and
netmask 0.0.0.0, in other words everything again. If they have a source
port of 53 also, we ACCEPT them directly.
As it is now, I ACCEPT incoming UDP packets from port 53, which is what we
use to do DNS lookups, without this we wouldn't be able to do domain name
lookups and we would be reversed to only use IP's. We don't want this
behaviour, hence we allow DNS, of course.
I personally also allow port 123, which is NTP or network time
protocol. This protocol is used to set your computer clock to the same
time as certain other time servers which have _very_ accurate
clocks. Though, most of you probably don't use this protocol, I'm allowing
it per default since i know there is some who actually do.
We currently also allowing port 2074, which is used for certain real-time
`multimedia' applications like speak freely which you can use to talk to
other people in real-time by using speakers and a microphone, or even
better, a headset.
Port 4000, well, it should be quite well known by now, it's the ICQ
protocol. I doubt there's any further need to explain what it is.
3.2.10 PREROUTING chain of the NAT table
The PREROUTING chain is pretty much what it says, it does filtering on
packets _before_ they actually hit the routing tables that sends them
onwards to the different INPUT/FORWARD/OUTPUT chains in the filter
table. This is a pretty good place to check if the packets are spoofed
etc.
First of all we check for obviously spoofed IP addresses, such as in case
we get packets from the Internet interface that claims to have a source IP
of 192.168.x.x, 10.x.x.x or 172.16.x.x, in such case, we drop them quicker
than hell since these IP's are reserved especially for local
intranets and definitely shouldn't be used on the Internet. This might be
used in the opposite direction, too, if we get an packet from $LAN_IFACE
that claims to _not_ come from an IP address in the $LAN_IP_RANGE, we might
drop that too.
3.2.11 INPUT chain
The INPUT chain as I've written it uses mostly other chains to do the hard
work. This way we don't get to much load from the ipfilters, and it will
work much better on slow machines which might else-wise drop packets at
high loads.
First of all we match all ICMP packets in the INPUT chain that comes on
the incoming interface $INET_IFACE, which in my case is eth0, and send
those to the icmp_packets, which was previously described. After this, we
do the same match for TCP packets on the $INET_IFACE and send those to the
tcp_packets chain, and after this all UDP packets gets sent to
udpincoming_packets chain.
Finally, we check for everything that comes from our $LOCALHOST_IP, which
would normally be 127.0.0.1 and ACCEPT all incoming traffic from there, do
the same for everything from $LAN_IP_RANGE, which in my case would be
192.168.0.0/24, and after this, something that some might consider a
security problem, I allow everything that comes from my own Internet IP
that is either ESTABLISHED or RELATED to some connection. Also, we allow
broadcast traffic from our LAN, some applications depends on it such as
Samba etc. These applications will not work properly without it.
Before we hit the default policy of the INPUT chain, we log it so we might
be able to find out about possible problems and or bugs. Either it might
be a packet that we just dont want to allow or it might be someone who's
doing something bad to us, or finally it might be a problem in our
firewall not allowing traffic that should be allowed. In either case we
want to know about it so it can be dealt with. Though, we don't log more
than 3 packets per minute as to not getting flooded with crap all over the
log files, also we set a prefix to all log entries so we know where it
came from.
Everything that hasn't yet been caught will be DROP'ed by the default
policy on the INPUT chain. The default policy was set quite some time
back, as you might remember.
3.2.12 OUTPUT chain
Since i know that there's pretty much no one but me using this box which
is partially used as a Firewall and a workstation currently, I allow
pretty much everything that goes out from it that has a source address
$LOCALHOST_IP, $LAN_IP or $STATIC_IP. Everything else might be
spoofed in some fashion, even though I doubt anyone that I know would do
it on my box. Last of all we log everything that gets dropped. If it does
get dropped, we'll sure as hell wanting to know about it for some reason
or another. Either it's a nasty error, or it's a weird packet that's
spoofed. Finally we DROP the packet in the default policy.
3.2.13 FORWARD chain
Even though I haven't actually setup a certain section in the rc.firewall
example file, I would like to comment on the few lines in there
anyways. As it is now, we first of all ACCEPT all packets coming from our
LAN with the following line:
/usr/local/sbin/iptables -A FORWARD -i $LAN_IFACE -j ACCEPT
So everything from our Localnet's interface gets ACCEPT'ed whatever the
circumstances. After this we allow everything in a state ESTABLISHED or
RELATED from everywhere, in other words, if we open a connection from our
LAN to something on the Internet, we allow the packets coming back from
that site that's either ESTABLISHED or RELATED but nothing else. And after
this we log everything and drop it. We log maximally 3 log entries per
minute as to not flood our own logs, and prefix them with a short line
that is possible to grep for in the logfiles. Also we log them with debug
level. We finally hit the default policy of the FORWARD chain that says to
DROP everything.
4 Appendix
4.1 Passive FTP but no DCC, extra read for the interested
This is one of the really nice parts about the new iptables support in the
2.4.x kernels, you can for example allow Passive FTP connections, but not
allow DCC send functions with the new state matching code. You may ask
yourself how, well, its quite simple once you get to think of it=). Just
compile the ip_conntrack_irc and ip_conntrack_ftp modules in the
kernel. What these modules does is that they add support to the conntrack
module so it can distinguish an passive FTP connection or an DCC send
connection, without these modules they can't recognize these
connections. If you for example want to allow passive FTP, but not DCC
send, you would load the ip_conntrack_ftp module, but not the
ip_conntrack_irc module and then do:
/sbin/iptables -A INPUT -p TCP -m state --state RELATED -j ACCEPT
to allow passive FTP but not DCC. If you would want to do the reversed,
you'd just load the ip_conntrack_irc module, but not the ip_conntrack_ftp
module.
4.2 Weird ISP's who use assigned IP's
I've added this since a friend of mine told me something i've totally
forgotten, certain stupid ISP's uses IP's assigned by IANA for their own
local networks. For example, the swedish ISP and phone monopoly Telia uses
this approach for example on their DNS servers, which uses the 10.x.x.x IP
range. The problem you'll most probably run into is that we, in this
script, don't allow connections from any IP's in the 10.x.x.x range to us,
because of spoofing possibilities. Well, here's unfortunately an example
where you actually might have to lift a bit on those rules. You might
just insert an ACCEPT rule above the spoof section to allow traffic from
those DNS servers, or you could just comment out that part of the script.
This is how it might look:
/usr/local/sbin/iptables -t nat -I PREROUTING -i eth1 -s 10.0.0.1/32 -j ACCEPT
I'd like to take my moment to bitch at these ISP's. These ranges are not
assigned for you to use for dumb stuff like this, at least not to my
knowledge, for large corporate sites it's more than ok, or your own
homenetwork, but you're not supposed to force us to open up ourself just
because of some whince of yours.
4.3 Updating and flushing your tables
If at some part you screw your iptables up, there are actually commands to
flush them, so you don't have to reboot. I've actually gotten this
question a couple times by now so I thought I'd answer it right here. If
you added a rule in error, you might just change the -A parameter to -D in
the line you added in error. IPTables will find the erroneus line and
erase it for you, in case you've got multiple lines looking exactly the
same in the chain, it erases the first instance it finds matching your
rule. If this is not the wanted behaviour you might try to use the -D
option as 'iptables -D INPUT 10' which will erase the 10th rule in the
INPUT chain.
There is also instances where you want to flush a whole chain, in this
case you might want to run the -F option. For example, 'iptables -F INPUT'
will erase the whole INPUT chain, though, this will not change the default
policy, so if this is set to DROP you'll block the whole INPUT chain if
used as above. To reset the chain policy, do as how you set it to DROP,
for example 'iptables -P INPUT ACCEPT'.
I've made a small script that will flush
and reset your iptables that you might consider using while setting up
your rc.firewall file properly. One thing though, if you start mucking
around in the mangle table, this script will not erase those, it's rather
simple to add the few lines needed to erase those but i've not added those
here since the mangle table is not used in my rc.firewall script so far.
4.4 Other resources and links
Here's a list of links to resources and where i've gotten information from
etc:
http://ods.dyndns.org/ipt_flow.html
- Graphics of traversing and explanation
/usr/src/linux/Documentation/networking/ip-sysctl.txt - system control via
/proc etc
http://netfilter.filewatcher.org
- The official site of iptables and netfilter
http://netfilter.filewatcher.org/netfilter-faq.html
- The official netfilter FAQ
http://netfilter.filewatcher.org/unreliable-guides/packet-filtering-HOWTO/index.html
- Unreliable guide to packet filtering
http://netfilter.filewatcher.org/unreliable-guides/NAT-HOWTO/index.html
- Unreliable Network Adress Translation HOWTO
http://netfilter.filewatcher.org/unreliable-guides/netfilter-hacking-HOWTO/index.html">
- Unreliable netfilter hacking HOWTO
http://lists.samba.org/mailman/listinfo/netfilter
- The netfilter mailing list for users
And of course the iptables source, documentation and individuals who
helped me.
5 Contributers
The following people I'd like to thank for the help on this document:
Marc Boucher,
For helping me out on some aspects on using the state matching code.
Frode E. Nyboe <fen@improbus.com>,
For greatly improving the rc.firewall rules and giving great inspiration
while i was to rewrite the ruleset and being the one who introduced the
multiple table traversing into the same file.
Chapman Brad <kakadu_croc@yahoo.com>,
Alexander W. Janssen <yalla@ynfonatic.de>,
Both for making me realize I was thinking wrong about how packets
traverses the basic NAT and filters tables and in which order they show
up.
Michiel Brandenburg <michielb@stack.nl>,
Myles Uyema <myles@puck.nether.net>,
Chapman Brad <kakadu_croc@yahoo.com>,
For helping me out with some of the state matching code and getting it to
work.
Kent 'Artech' Stahre <artech@boingworld.com> ,
For helping me out with the graphics. I know I suck at graphics, and
you're better than most I know who do graphics;). Also thanks for checking
the tutorial for errors etc.
Jeremy 'Spliffy' Smith <di99smje@chl.chalmers.se> ,
For giving me hints at stuff that might screw up for people and for trying
it out and checking for errors in what I've written.
And of course everyone else I talked to and asked for comments on
this file, sorry for not mentioning everyone.
|
|