  Linux IPCHAINS-HOWTO
  Paul Russell, Paul.Russell@rustcorp.com.au
  v0.6, Sun May 17 14:29:26 CST 1998

  This document aims to describe how to obtain, install and configure
  the enhanced generic IP firewalling chains software for Linux, and
  some ideas on how you might use them.
  ______________________________________________________________________

  Table of Contents
























































  1. Introduction

     1.1 What?
     1.2 Why?
     1.3 How?
     1.4 Where?

  2. Packet Filtering Basics

     2.1 What?
     2.2 Why?
     2.3 How?
        2.3.1 A Kernel With Packet Filtering
        2.3.2 ``ipchains''

  3. Generic IP Firewalling Chains

     3.1 How Packets Traverse the Filters
        3.1.1 Using ipchains
        3.1.2 Operations on a Single Rule
        3.1.3 Filtering Specifications
           3.1.3.1 Specifying Source and Destination IP Addresses
           3.1.3.2 Specifying Inversion
           3.1.3.3 Specifying Protocol
              3.1.3.3.1 Specifying UDP and TCP Ports
              3.1.3.3.2 Specifying ICMP Type & Code
           3.1.3.4 Specifying an Interface
           3.1.3.5 Specifying TCP SYN Packets Only
           3.1.3.6 Handling Fragments
        3.1.4 Filtering Side Effects
           3.1.4.1 Specifying a Target
           3.1.4.2 Logging Packets
           3.1.4.3 Manipulating the Type Of Service
           3.1.4.4 Marking a Packet
           3.1.4.5 Operations on an Entire Chain
           3.1.4.6 Creating a New Chain
           3.1.4.7 Deleting a Chain
           3.1.4.8 Flushing a Chain
           3.1.4.9 Listing a Chain
           3.1.4.10 Resetting (Zeroing) Counters
           3.1.4.11 Setting Policy
        3.1.5 Operations on Masquerading
        3.1.6 Checking a Packet
        3.1.7 Multiple Rules at Once and Watching What Happens
     3.2 Useful Examples
        3.2.1 Using ``ipchains-save''
        3.2.2 Using ``ipchains-restore''

  4. Miscellaneous

     4.1 How to Organise Your Firewall Rules
     4.2 What NOT to Filter Out
        4.2.1 ICMP Packets
        4.2.2 DNS Replies
        4.2.3 FTP Nightmares
     4.3 Filtering out Ping of Death
     4.4 Filtering out Teardrop and Bonk
     4.5 Filtering out Fragment Bombs
     4.6 Changing Firewall Rules
     4.7 Advanced Projects
     4.8 Future Enhancements

  5. Appendix - Differences between ipchains and ipfwadm

     5.1 Quick-Reference Table
     5.2 Examples of translated ipfwadm commands
  6. Appendix - Using the `ipfwadm-wrapper' script

  7. Appendix - Thanks



  ______________________________________________________________________

  11..  IInnttrroodduuccttiioonn

  This is the Linux IPCHAINS-HOWTO.  You should read the Linux
  NET-3-HOWTO as well.  The IP-Masquerading HOWTO, the PPP-HOWTO and the
  Ethernet-HOWTO might make interesting reading.  (Then again, so might
  the alt.fan.bigfoot FAQ).


  If packet filtering is passe to you, read Section ``Why?'', Section
  ``How?'', and scan through the titles in Section ``Generic IP
  Firewalling Chains''.


  If you are converting from ipfwadm, read Section ``Introduction'',
  Section ``How?'', and Appendices ``Differences between ipchains and
  ipfwadm'' and ``Using the `ipfwadm-wrapper' script''.


  11..11..  WWhhaatt??

  Linux _i_p_c_h_a_i_n_s is a rewrite of the Linux IPv4 firewalling code (which
  was mainly stolen from BSD) and a rewrite of ipfwadm, which was a
  rewrite of BSD's ipfw, I believe.


  11..22..  WWhhyy??

  The current Linux firewalling code doesn't deal with fragments, has
  32-bit counters (on Intel at least), doesn't allow specification of
  protocols other than TCP, UDP or ICMP, can't make large changes
  atomically, can't specify inverse rules, has some strange quirks, and
  can be tough to manage (making it prone to user error).


  11..33..  HHooww??

  Currently the code is in the mainstream kernel from 2.1.102.  For the
  2.0 kernel series, you will need to download a kernel patch from the
  web page.


  11..44..  WWhheerree??

  The official page is The Linux Generic IP Firewall Chains Page
  <http://www.adelaide.net.au/~rustcorp/ipfwchains>


  If I had access to a large anon. ftp server I'd put the software
  there, but it's not large, so http transfer is bearable.


  There is a mailing list for bug reports, discussion, development and
  usage.  Join the mailing list by sending a message containing the word
  "subscribe" to ipchains-request at wantree.com.au.  To mail to the
  list use `ipchains' instead of `ipchains-request'.



  22..  PPaacckkeett FFiilltteerriinngg BBaassiiccss

  22..11..  WWhhaatt??

  All traffic through a network is sent in the form of packets.  For
  example, downloading this package (say it's 50k long) might cause you
  to receive 36 or so packets of 1460 bytes each, (to pull numbers at
  random).


  The start of each packet says where it's going, where it came from,
  the type of the packet, and other administrative details.  This start
  of the packet is called the `header'.  The rest of the packet,
  containing the actual data being transmitted, is usually called the
  `body'.


  Some protocols, such TCP, which is used for web traffic, mail, and
  remote logins, use the concept of a `connection' - before any packets
  with actual data are sent, various setup packets (with special
  headers) are exchanged saying `I want to connect', `OK' and `Thanks'.
  Then normal packets are exchanged.


  A packet filter is a piece of software which looks at the _h_e_a_d_e_r of
  packets as they pass through, and decide the fate of the entire
  packet.  It might decide to deny the packet (ie. discard the packet as
  if it had never received it), let the packet go through, or reject the
  packet (like deny, but tell the source of the packet that it has done
  so).


  Under Linux, packet filtering in built into the kernel, and there are
  a few trickier things we can do with packets, but the general
  principle of looking at the headers and deciding the fate of the
  packet is still there.


  22..22..  WWhhyy??

  Control.  Security.  Watchfulness.



     CCoonnttrrooll::
        when you are using a Linux box to connect your internal network
        to another network (say, the Internet) you have an opportunity
        to allow certain types of traffic, and disallow others.  For
        example, the header of a packet contains the destination address
        of the packet, so you can prevent packets going to a certain
        part of the outside network.  As another example, I use Netscape
        to access the Dilbert archives.  There are advertisements from
        doubleclick.net on the page, and Netscape happily wastes my time
        by cheerfully downloading them.  Telling the packet filter not
        to allow any packets to or from the addresses owned by
        doubleclick.net solves that problem (there are better ways of
        doing this though).


     SSeeccuurriittyy::
        when your Linux box is the only thing between the chaos of the
        Internet and your nice, orderly network, it's nice to know you
        can restrict what comes tromping in your door.  For example, you
        might allow anything to go out from your network, but you might
        be worried about the dreaded `ping of death' coming in from
        malicious outsiders.  As another example, you might not want
        outsiders telnetting to your Linux box, even though all your
        accounts have passwords; maybe you want (like most people) to be
        an observer on the Internet, and not a server (willing or
        otherwise) -- simply don't let anyone connect in, by having the
        packet filter reject incoming packets used to set up
        connections.


     WWaattcchhffuullnneessss::
        sometimes a badly configured machine on the local network will
        decide to spew packets to the outside world.  It's nice to tell
        the packet filter to let you know if anything abnormal occurs;
        maybe you can do something about it, or maybe you're just
        curious by nature.


  22..33..  HHooww??

  22..33..11..  AA KKeerrnneell WWiitthh PPaacckkeett FFiilltteerriinngg

  You need a kernel which has the new Generic IP Firewall Chains in it.
  You can tell if the kernel you are running right now has this
  installed by looking for the file `/proc/net/ip_fwchains'.  If it
  exists, you're in.


  If not, you need to make a kernel that has Generic IP Firewall Chains.
  You need to download the kernel, apply the patch from the web page
  listed above, and set the configuration as detailed below.  If you
  don't know how to do this, don't panic - read the Kernel-HOWTO.


  The configuration options you will need to set are:


  ______________________________________________________________________
          CONFIG_EXPERIMENTAL=y
          CONFIG_FIREWALL=y
          CONFIG_IP_FIREWALL=y
          CONFIG_IP_FIREWALL_CHAINS=y
  ______________________________________________________________________




  The tool `ipchains' talks to the kernel and tells it what packets to
  filter.  Unless you are a programmer, or overly curious, this is how
  you will control the packet filtering.


  22..33..22..  ````iippcchhaaiinnss''''

  This tool replaces `ipfwadm' used for the old IP Firewall code.  The
  package also contains a shell script called `ipfwadm-wrapper' which
  allows you to do packet filtering as it was done before.  You should
  NOT use this script unless you want a quick way of upgrading a system
  which uses ipfwadm (it's slower, and doesn't check arguments, etc).
  In that case, you don't need this HOWTO much either.  See Appendix
  ``Differences between ipchains and ipfwadm'' and Appendix ``Using the
  `ipfwadm-wrapper' script'' for more details on ipfwadm issues.


  33..  GGeenneerriicc IIPP FFiirreewwaalllliinngg CChhaaiinnss

  This section describes all you really need to know to build a packet
  filter that meets your needs.
  33..11..  HHooww PPaacckkeettss TTrraavveerrssee tthhee FFiilltteerrss

  The kernel starts with three lists of rules (called `firewall chains'
  or just `chains').  The three chains are called `input', `output' and
  `forward'.  When a packet comes in (say, through the Ethernet card)
  the kernel uses the `input' chain to decide its fate.  If it survives
  that step, then the kernel decides where to send the packet next.  If
  it is destined for another machine, it consults the `forward' chain.
  Finally, just before a packet is to go out, the kernel consults the
  `output' chain.


  A chain is a checklist of `rules'.  Each rule says `if the packet
  header looks like this, then here's what to do with the packet'.  If
  the rule doesn't match the packet, then the next rule in the chain is
  consulted.  Finally, if there are no more rules to consult, then the
  kernel looks at the chain `policy' to decide what to do.  In a
  security-conscious system, this policy usually tells the kernel to
  reject or deny the packet.


  For ASCII-art fans, this shown the complete path of a packet coming
  into a machine.


                       ACCEPT/
                      REDIRECT                                        ACCEPT
  --> C --> S --> ______ --> D --> ~~~~~~~~ --> local ------> _______ -->
      h  -> a    |input |    e    {Routing } |  __|____ -->->|output |
      e  |  n    |Chain |    m    {Decision} | |forward|   | |Chain  |
      c  |  i    |______|    a     ~~~~~~~~  | |Chain  |   | |_______|
      k  |  t       |        s        |      | |_______|   |     |
      s  |  y       |        q        |      |     |       |     |
      u  |  |       v        e        v      |     |       |     v
      m  |  |     DENY/      r  Local Process|     v       |   DENY/
      |  |  v    REJECT      a        |-------   DENY/     |  REJECT
      |  |DENY               d        |         REJECT     |
      v  |                   e -------+---------------------
     DENY|                            |
         ------------------------------


  Here is a blow-by-blow description of each stage:


     CChheecckkssuumm::
        This is a test that the packet hasn't been corrupted in some
        way.  If it has, it is denied.


     SSaanniittyy::
        There is actually one of these sanity checks before each
        firewall chain, but the input chain's is the most important.
        Some malformed packets might confuse the rule-checking code, and
        these are denied here (a message is printed to the syslog if
        this happens).


     iinnppuutt CChhaaiinn::
        This is the first firewall chain against which the packet will
        be tested.  If the verdict of the chain is not DENY or REJECT,
        the packet continues on.


     DDeemmaassqquueerraaddee::
        If the packet is a reply to a previously masqueraded packet, it
        is demasqueraded, and skips straight to the output Chain.  If
        you don't use IP Masquerading, you can mentally erase this from
        the diagram.


     RRoouuttiinngg DDeecciissiioonn::
        The destination field is examined by the routing code, to decide
        if this packet should go to a local process (see Local Process
        below) or forwarded to a remote machine (see forward Chain
        below).


     LLooccaall PPrroocceessss::
        A process running on the machine can receive packets after the
        Routing Decision step, and can send packets (which go through
        the output then input chains with interface set to `lo' if they
        are destined for a local process, otherwise they only traverse
        the output chain).  This is inter-process chain traversal isn't
        fully shown on the diagram, as it is too icky.


     llooccaall::
        If the packet was not created by a local process, then the
        forward Chain is checked, otherwise the packet goes straight to
        the output Chain.


     ffoorrwwaarrdd CChhaaiinn::
        This chain is traversed for any packets which are attempting to
        pass through this machine to another.


     oouuttppuutt CChhaaiinn::
        This chain is traversed for all packets just before they are
        sent out.


  33..11..11..  UUssiinngg iippcchhaaiinnss

  First, check that you have the version of ipchains that this document
  refers to:



       $ ipchains --version
       ipchains 1.3.3, 16-May-1998





  ipchains has a fairly detailed manual page ("man ipchains"), and if
  you need more detail on particulars, you can check out the programming
  interface ("man 4 ipfw"), or the file "net/ipv4/ip_fwtrees.c" in the
  kernel source, which is (obviously) authoritative.


  There are several different things you can do with ipchains.  First
  the operations to manage whole chains.  You start with three built-in
  chains `input', `output' and `forward' which you can't delete.


  1. Create a new chain (-N).

  2. Delete an empty chain (-X).

  3. Change the policy for a built-in chain. (-P).

  4. List the rules in a chain (-L).

  5. Flush the rules out of a chain (-F).

  6. Zero the packet and byte counters on all rules in a chain (-Z).

  There are several ways to manipulate rules inside a chain:


  1. Append a new rule to a chain (-A).

  2. Insert a new rule at some position in a chain (-I).

  3. Replace a rule at some position in a chain (-R).

  4. Delete a rule at some position in a chain (-D).

  5. Delete the first rule that matches in a chain (-D).

  There are a few operations for masquerading, which are in ipchains for
  want of a good place to put them:


  1. List the currently masqueraded connections (-M -L).

  2. Set masquerading timeout values (-M -S).

  The final (and perhaps the most useful) function allows you to check
  what would happen to a given packet if it were to traverse a given
  chain.


  33..11..22..  OOppeerraattiioonnss oonn aa SSiinnggllee RRuullee

  This is the bread-and-butter of ipchains; manipulating rules.  Most
  commonly, you will probably use the append (-A) and delete (-D)
  commands.  The others (-I for insert and -R for replace) are simple
  extensions of these concepts.


  Each rule specifies a set of conditions the packet must meet, and what
  to do if it meets them (a `target').  For example, you might want to
  deny all ICMP packets coming from the IP address 127.0.0.1.  So in
  this case our conditions are that the protocol must be ICMP and that
  the source address must be 127.0.0.1.  Our target is "DENY".


  127.0.0.1 is the `loopback' interface, which you will have even if you
  have no real network connection.  You can use the `ping' program to
  generate such packets (it simply sends an ICMP type 8 (echo request)
  which all cooperative hosts should obligingly respond to with an ICMP
  type 0 (echo reply) packet).  This makes it useful for testing.












  # ping -c 1 127.0.0.1
  PING 127.0.0.1 (127.0.0.1): 56 data bytes
  64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms

  --- 127.0.0.1 ping statistics ---
  1 packets transmitted, 1 packets received, 0% packet loss
  round-trip min/avg/max = 0.2/0.2/0.2 ms
  # ipchains -A input -s 127.0.0.1 -p icmp -j DENY
  # ping -c 1 127.0.0.1
  PING 127.0.0.1 (127.0.0.1): 56 data bytes

  --- 127.0.0.1 ping statistics ---
  1 packets transmitted, 0 packets received, 100% packet loss
  #




  You can see here that the first ping succeeds (the `-c 1' tells ping
  to only send a single packet).


  Then we append (-A) to the `input' chain, a rule specifying that for
  packets from 127.0.0.1 (`-s 127.0.0.1') with protocol ICMP (`-p ICMP')
  we should jump to DENY (`-j DENY').


  Then we test our rule, using the second ping.  There will be a pause
  before the program gives up waiting for a response that will never
  come.


  We can delete the rule in one of two ways.  Firstly, since we know
  that it is the only rule in the input chain, we can use a numbered
  delete, as in:


               # ipchains -D input 1
               #




  To delete rule number 1 in the input chain.


  The second way is to mirror the -A command, but replacing the -A with
  -D.  This is useful when you have a complex chain of rules and you
  don't want to have to count them to figure out that it's rule 37 that
  you want to get rid of.  In this case, we would use:


               # ipchains -D input -s 127.0.0.1 -p icmp -j DENY
               #




  The syntax of -D must have exactly the same options as the -A (or -I
  or -R) command.  If there are multiple identical rules in the same
  chain, only the first will be deleted.





  33..11..33..  FFiilltteerriinngg SSppeecciiffiiccaattiioonnss

  We have seen the use of `-p' to specify protocol, and `-s' to specify
  source address, but there are other options we can use to specify
  packet characteristics.  What follows is an exhaustive compendium.


  33..11..33..11..  SSppeecciiffyyiinngg SSoouurrccee aanndd DDeessttiinnaattiioonn IIPP AAddddrreesssseess

  Source (-s) and destination (-d) IP addresses can be specified in four
  ways.  The most common way is to use the full name, such as
  `localhost' or `www.linuxhq.com'.  The second way is to specify the IP
  address such as `127.0.0.1'.


  The third and fourth ways allow specification of a group of IP
  addresses, such as `199.95.207.0/24' or `199.95.207.0/255.255.255.0'.
  These both specify any IP address from 192.95.207.0 to 192.95.207.255
  inclusive; the digits after the `/' tell which parts of the IP address
  are significant.  `/32' or `/255.255.255.255' is the default (match
  all of the IP address).  To specify any IP address at all `/0' can be
  used, like so:


               # ipchains -A input -s 0/0 -j DENY
               #




  This is rarely used, as the effect above is the same as not specifying
  the `-s' option at all.


  33..11..33..22..  SSppeecciiffyyiinngg IInnvveerrssiioonn

  Many flags, including the `-s' and `-d' flags can have their arguments
  preceded by `!' (pronounced `not') to match addresses NOT equal to the
  ones given.  For example. `-s ! localhost' matches any packet not
  coming from localhost.


  33..11..33..33..  SSppeecciiffyyiinngg PPrroottooccooll

  The protocol can be specified with the `-p' flag.  Protocol can be a
  number (if you know the numeric protocol values for IP) or a name for
  the special cases of `TCP', `UDP' or `ICMP'.  Case doesn't matter, so
  `tcp' works as well as `TCP'.


  The protocol name can be prefixed by a `!', to invert it, such as `-p
  ! TCP'.


  33..11..33..33..11..  SSppeecciiffyyiinngg UUDDPP aanndd TTCCPP PPoorrttss

  For the special case where a protocol of TCP or UDP is specified,
  there can be an extra argument indicating the TCP or UDP port, or an
  (inclusive) range of ports (but see ``Handling Fragments'' below).  A
  range is represented using a `:' character, such as `6000:6010', which
  covers 11 port numbers, from 6000 to 6010 inclusive.  If the lower
  bound is omitted, it defaults to 0.  If the upper bound is omitted, it
  defaults to 65535.  So to specify TCP connections coming from ports
  under 1024, the syntax would be as `-p TCP -s 0.0.0.0/0 :1024'.  Port
  numbers can be specified by name, eg. `www'.

  Note that the port specification can be preceded by a `!', which
  inverts it.  So to specify every TCP packet BUT a WWW packet, you
  would specify

  -p TCP -d 0.0.0.0/0 ! www



  It is important to realise that the specification


  -p TCP -d ! 192.168.1.1 www



  is very different from

  -p TCP -d 192.168.1.1 ! www



  The first specifies any TCP packet to the WWW port on any machine but
  192.168.1.1.  The second specifies any TCP connection to any port on
  192.168.1.1 but the WWW port.


  Finally, this case means not the WWW port and not 192.168.1.1:

  -p TCP -d ! 192.168.1.1 ! www




  33..11..33..33..22..  SSppeecciiffyyiinngg IICCMMPP TTyyppee && CCooddee

  ICMP also allows an optional argument, but as ICMP doesn't have ports,
  they have a different meaning.


  You can specify them as ICMP names (use `ipchains -h icmp' to list the
  names) after the `-s' option, or as a numeric ICMP type and code,
  where the type follows the `-s' option and the code follows the `-d'
  option.


  The ICMP names are fairly long: you only need use enough letters to
  make the name distinct from any other.


  Here is a small table of some of the most common ICMP packets:


       Number  Name                     Required by

       0       echo-reply               ping
       3       destination-unreachable  Any TCP/UDP traffic.
       5       redirect                 routing if not running routing daemon
       8       echo-request             ping
       11      time-exceeded            traceroute




  Note that the ICMP names cannot be preceeded by `!' at the moment.


  DO NOT DO NOT DO NOT block all ICMP type 3 messages!  (See ``ICMP
  Packets'' below).


  33..11..33..44..  SSppeecciiffyyiinngg aann IInntteerrffaaccee

  The `-i' option specifies the name of an interface to match.  The
  interface for incoming packets (ie. packets traversing the `input'
  chain) is considered to be the interface they came in on.  Logically,
  the interface for outgoing packets (packets traversing the `output'
  chain) is the interface they will go out on.  The interface for
  packets traversing the `forward' chain is also the interface they will
  go out on; a fairly arbitrary decision it seems to me.


  It is perfectly legal to specify an interface that currently does not
  exist; the rule will not match anything until the device comes up.
  This is extremely useful for dial-up ppp links (usually interface
  `ppp0') and the like.


  As a special case, an interface name ending with a `+' will match all
  interfaces (whether they currently exist or not) which begin with that
  string.  For example, to specify a rule which matches all PPP
  interfaces, the `-i ppp+' option is used.


  The interface name can be preceded by a `!' to match a packet which
  does NOT match the specified interface(s).


  33..11..33..55..  SSppeecciiffyyiinngg TTCCPP SSYYNN PPaacckkeettss OOnnllyy

  It is sometimes useful to allow TCP connections in one direction, but
  not the other.  For example, you might want to allow connections to an
  external WWW server, but not connections from that server.


  The naive approach would be to block TCP packets coming from the
  server.  Unfortunately, TCP connections require packets going in both
  directions to work at all.


  The solution is to block only the packets used to request a
  connection.  These packets are called SYN packets (ok, technically
  they're packets with the SYN flag set, and the FIN and ACK flags
  cleared).  By disallowing only these packets, we can stop attempted
  connections in their tracks.


  The `-y' flag is used for this: it is only valid for rules which
  specify TCP as their protocol.  For example, to specify TCP connection
  attempts from 192.168.1.1:

  -p TCP -s 192.168.1.1 -y




  Once again, this flag can be inverted by preceding it with a `!',
  which means every packet other than the connection initiation.





  33..11..33..66..  HHaannddlliinngg FFrraaggmmeennttss

  Sometimes a packet is too large to fit down a wire all at once.  When
  this happens, the packet is divided into `fragments', and sent as
  multiple packets.  The other end reassembles the fragments to
  reconstruct the whole packet.


  The problem with fragments is that some of the specifications listed
  above (in particular, source port, destinations port, ICMP type, ICMP
  code, or TCP SYN flag) require the kernel to peek at the start of the
  packet, which is only contained in the first fragment.


  If your machine is the only connection to an external network, then
  you can tell the Linux kernel to reassemble all fragments which pass
  through it, by compiling the kernel with `IP: always defragment' set
  to `Y'.  This sidesteps the issue neatly.


  Otherwise, it is important to understand how fragments get treated by
  the filtering rules.  Any filtering rule that asks for information we
  don't have will NOT match.  This means that the first fragment is
  treated like any other packet.  Second and further fragments won't.
  Thus a rule `-p TCP -s 192.168.1.1 www' (specifying a source port of
  `www') will never match a fragment (other than the first fragment).
  Neither will the opposite rule `-p TCP -s 192.168.1.1 ! www'.


  However, you can specify a rule specifically for second and further
  fragments, using the `-f' flag.  Obviously, it is illegal to specify a
  TCP or UDP port, ICMP type, ICMP code or TCP SYN flag in such a
  fragment rule.


  It is also legal to specify that a rule does NOT apply to second and
  further fragments, by preceding the `-f' with `!'.


  Usually it is regarded as safe to let second and further fragments
  through, since filtering will effect the first fragment, and thus
  prevent reassembly on the target host, however, bugs have been known
  to allow crashing of machines simply by sending fragments.  Your call.


  Note for network-heads: malformed packets (TCP, UDP and ICMP packets
  too short for the firewalling code to read the ports or ICMP code and
  type) are treated as fragments as well.  Only TCP fragments starting
  at position 8 are explicitly dropped by the firewall code (a message
  should appear in the syslog if this occurs).


  As an example, the following rule will drop any fragments going to
  192.168.1.1:




       # ipchains -A output -f -D 192.168.1.1 -j DENY
       #






  33..11..44..  FFiilltteerriinngg SSiiddee EEffffeeccttss

  OK, so now we know all the ways we can match a packet using a rule.
  If a packet matches a rule, the following things happen:


  1. The byte counter for that rule is increased by the size of the
     packet (header and all).

  2. The packet counter for that rule is incremented.

  3. If the rule requests it, the packet is logged.

  4. If the rule requests it, the packet's Type Of Service field is
     changed.

  5. If the rule requests it, the packet is marked (not in 2.0 kernel
     series).

  6. The rule target is examined to decide what to do to the packet
     next.


  For variety, I'll address these in order of importance.


  33..11..44..11..  SSppeecciiffyyiinngg aa TTaarrggeett

  A `target' tells the kernel what to do with a packet that matches a
  rule.  ipchains uses `-j' (think "jump-to") for the target
  specification.


  The simplest case is when there is no target specified.  This type of
  rule (often called an `accounting' rule) is useful for simply counting
  a certain type of packet.  Whether this rule matches or not, the
  kernel simply examines the next rule in the chain.  For example, to
  count the number of packets from 192.168.1.1, we could do this:


       # ipchains -A input -s 192.168.1.1
       #





  (Using `ipchains -L -v' we can see the byte and packet counters
  associated with each rule).


  There are six special targets.  The first three, `ACCEPT', `REJECT'
  and `DENY' are fairly simple.  ACCEPT allows the packet through.  DENY
  drops the packet as if it had never been received.  REJECT drops the
  packet, but (if it's not an ICMP packet) generates an ICMP reply to
  the source to tell it that the destination was unreachable.


  The next one, `MASQ' tells the kernel to masquerade the packet.  For
  this to work, your kernel needs to be compiled with IP Masquerading
  enabled.  For details on this, see the Masquerading-HOWTO and the
  Appendix ``Differences between ipchains and ipfwadm''.  This target is
  only valid for packets traversing the `forward' chain.



  The other major special target is `REDIRECT' which tells the kernel to
  send a packet to a local port instead of wherever it was heading.
  This can only be specified for rules specifying TCP or UDP as their
  protocol.  Optionally, a port (name or number) can be specified
  following `-j REDIRECT' which will cause the packet to be redirected
  to that particular port, even if it was addressed to another port.
  This target is only valid for packets traversing the `input' chain.


  The final special target is `RETURN' which is identical to falling off
  the end of the chain immediately.  (See ``Setting Policy'' below).


  Any other target indicates a user-defined chain (as described in
  ``Operations on an Entire Chain'' below).  The packet will begin
  traversing the rules in that chain.  If that chain doesn't decide the
  fate of the packet, then once traversal on that chain has finished,
  traversal resumes on the next rule in the current chain.


  Time for more ASCII art.  Consider two (silly) chains: `input' (the
  built-in chain) and `Test' (a user-defined chain).


           `input'                         `Test'
          ----------------------------    ----------------------------
          | Rule1: -p ICMP -j REJECT |    | Rule1: -s 192.168.1.1    |
          |--------------------------|    |--------------------------|
          | Rule2: -p TCP -j Test    |    | Rule2: -d 192.168.1.1    |
          |--------------------------|    ----------------------------
          | Rule3: -p UDP -j DENY    |
          ----------------------------




  Consider a TCP packet coming from 192.168.1.1, going to 1.2.3.4.  It
  enters the input chain, and gets tested against Rule1 - no match.
  Rule2 matches, and its target is `Test', so the next rule examined is
  the start of `Test'.  Rule1 in Test matches, but doesn't specify a
  target, so the next rule is examined, Rule2.  This doesn't match, so
  we have reached the end of the chain.  We return to the `input' chain,
  where we had just examined Rule2, so we now examine Rule3, which
  doesn't match either.


  So the packet path is:

                                  v    __________________________
           `input'                |   /    `Test'                v
          ------------------------|--/    -----------------------|----
          | Rule1                 | /|    | Rule1                |   |
          |-----------------------|/-|    |----------------------|---|
          | Rule2                 /  |    | Rule2                |   |
          |--------------------------|    -----------------------v----
          | Rule3                 /--+___________________________/
          ------------------------|---
                                  v




  See the section ``How to Organise Your Firewall Rules'' for ways to
  use user-defined chains effectively.


  33..11..44..22..  LLooggggiinngg PPaacckkeettss

  This is a side effect that matching a rule can have; you can have the
  matching packet logged using the `-l' flag.  You will usually not want
  this for routine packets, but it is a useful feature if you want to
  look for exceptional events (see `man klogd' or `man dmesg').


  33..11..44..33..  MMaanniippuullaattiinngg tthhee TTyyppee OOff SSeerrvviiccee

  There are four seldom-used bits in the IP header, called the Type of
  Service (TOS) bits.  The effect the way packets are treated; the four
  bits are "Minimum Delay", "Maximum Throughput", "Maximum Reliability"
  and "Minimum Cost".  Only one of these bits is allowed to be set.  Rob
  van Nieuwkerk, the author of the TOS-mangling code, puts it as
  follows:


       Especially the "Minimum Delay" is important for me.  I
       switch it on for "interactive" packets in my upstream
       (Linux) router.  I'm behind a 33k6 modem link.  Linux pri-
       oritises packets in 3 queues.  This way I get acceptable
       interactive performance while doing bulk downloads at the
       same time.  (It could even be better if there wasn't such a
       big queue in the serial driver, but latency is kept down 1.5
       seconds now).



  The most common use is to set telnet & ftp control connections to
  "Minimum Delay" and FTP data to "Maximum Throughput".  This would be
  done as follows:



       ipchains -A output -p tcp -d 0.0.0.0/0 telnet -t 0x01 0x10
       ipchains -A output -p tcp -d 0.0.0.0/0 ftp -t 0x01 0x10
       ipchains -A output -p tcp -s 0.0.0.0/0 ftp-data -t 0x01 0x08





  The `-t' flag takes two extra parameters, both in hexadecimal.  These
  allow complex twiddling of the TOS bits: the first mask is ANDed with
  the packet's current TOS, and then the second mask is XORed with it.
  If this is too confusing, just use the following table:



       TOS Name                Value           Typical Uses

       Minimum Delay           0x01 0x10       ftp, telnet
       Maximum Throughput      0x01 0x08       ftp-data
       Maximum Reliability     0x01 0x04       snmp
       Minimum Cost            0x01 0x02       nntp





  33..11..44..44..  MMaarrkkiinngg aa PPaacckkeett

  This is currently unused, but it is my hope that it will allow complex
  and powerful interactions with Alexey Kuznetsov's new Quality of
  Service implementation which replaces the Traffic Shaper in the v2.1
  kernels.  Thus, it is ignored altogether in the 2.0 kernel series.


  33..11..44..55..  OOppeerraattiioonnss oonn aann EEnnttiirree CChhaaiinn

  A very useful feature of ipchains is the ability to group related
  rules into chains.  You can call the chains whatever you want, as long
  as the names don't clash with the built-in chains (`input', `output'
  and `forward') or the targets (`MASQ', `REDIRECT', `ACCEPT', `DENY',
  `REJECT' or `RETURN').  I suggest avoiding upper-case labels entirely,
  since I may use these for future extensions.  The chain name can be up
  to 8 characters long.


  33..11..44..66..  CCrreeaattiinngg aa NNeeww CChhaaiinn

  Let's create a new chain.  Because I am such an imaginative fellow,
  I'll call it `test'.



       # ipchains -N test
       #





  It's that simple.  Now you can put rules in it as detailed above.


  33..11..44..77..  DDeelleettiinngg aa CChhaaiinn

  Deleting a chain is simple as well.



       # ipchains -X test
       #




  Why `-X'?  Well, all the good letters were taken.


  There are a couple of restrictions to deleting chains: they must be
  empty (see ``Flushing a Chain'' below) and they must not be the target
  of any rule.  You can't delete any of the three built-in chains.


  33..11..44..88..  FFlluusshhiinngg aa CChhaaiinn

  There is a simple way of emptying all rules out of a chain, using the
  `-F' command.



               # ipchains -F forward
               #






  If you don't specify a chain, then ALL chains will be flushed.


  33..11..44..99..  LLiissttiinngg aa CChhaaiinn

  You can list all the rules in a chain by using the `-L' command.



       # ipchains -L input
       Chain input (refcnt = 1): (policy ACCEPT)
       target     prot opt    source                destination           ports
       ACCEPT     icmp -----  anywhere              anywhere              any
       # ipchains -L test
       Chain test (refcnt = 0):
       target     prot opt    source                destination           ports
       DENY       icmp -----  localnet/24           anywhere              any
       #





  The "refcnt" listed for `test' is the number of rules which have
  `test' as their target.  This must be zero (and the chain be empty)
  before this chain can be deleted.


  If the chain name is omitted, all chains are listed, even empty ones.


  There are three options which can accompany `-L'.  The `-n' (numeric)
  option is very useful as it prevents ipchains from trying to lookup
  the IP addresses, which (if you are using DNS like most people) will
  cause large delays if your DNS is not set up properly, or you have
  filtered out DNS requests.  It also causes ports to be printed out as
  numbers rather than names.


  The `-v' options shows you all the details of the rules, such as the
  the packet and byte counters, the TOS masks, the interface, and the
  packet mark.  Otherwise these values are omitted.  For example:



       # ipchains -v -L input
       Chain input (refcnt = 1): (policy ACCEPT)
        pkts bytes target     prot opt   tosa tosx  ifname    mark        source                destination           ports
          10   840 ACCEPT     icmp ----- 0xFF 0x00  lo                    anywhere              anywhere              any





  Note that the packet and byte counters are printed out using the
  suffixes `K', `M' or `G' for 1000, 1,000,000 and 1,000,000,000
  respectively.  Using the `-x' (expand numbers) flag as well prints the
  full numbers, no matter how large they are.


  33..11..44..1100..  RReesseettttiinngg ((ZZeerrooiinngg)) CCoouunntteerrss

  It is useful to be able to reset the counters.  This can be done with
  the `-Z' (zero counters) option.  For example:


       # ipchains -v -L input
       Chain input (refcnt = 1): (policy ACCEPT)
        pkts bytes target     prot opt   tosa tosx  ifname    mark        source                destination           ports
          10   840 ACCEPT     icmp ----- 0xFF 0x00  lo                    anywhere              anywhere              any
       # ipchains -Z input
       # ipchains -v -L input
       Chain input (refcnt = 1): (policy ACCEPT)
        pkts bytes target     prot opt   tosa tosx  ifname    mark        source                destination           ports
           0     0 ACCEPT     icmp ----- 0xFF 0x00  lo                    anywhere              anywhere              any
       #





  The problem with this approach is that sometimes you need to know the
  counter values immediately before they are reset.  In the above
  example, some packets could pass through between the `-L' and `-Z'
  commands.  For this reason, you can use the `-L' and `-Z' _T_O_G_E_T_H_E_R, to
  reset the counters while reading them.  Unfortunately, if you do this,
  you can't operate on a single chain: you have to list and zero all the
  chains at once.



       # ipchains -L -v -Z
       Chain input (policy ACCEPT):
        pkts bytes target     prot opt   tosa tosx  ifname    mark        source                destination           ports
          10   840 ACCEPT     icmp ----- 0xFF 0x00  lo                    anywhere              anywhere              any

       Chain forward (refcnt = 1): (policy ACCEPT)
       Chain output (refcnt = 1): (policy ACCEPT)
       Chain test (refcnt = 0):
           0     0 DENY       icmp ----- 0xFF 0x00  ppp0                  localnet/24           anywhere              any
       # ipchains -L -v
       Chain input (policy ACCEPT):
        pkts bytes target     prot opt   tosa tosx  ifname    mark        source                destination           ports
          10   840 ACCEPT     icmp ----- 0xFF 0x00  lo                    anywhere              anywhere              any

       Chain forward (refcnt = 1): (policy ACCEPT)
       Chain output (refcnt = 1): (policy ACCEPT)
       Chain test (refcnt = 0):
           0     0 DENY       icmp ----- 0xFF 0x00  ppp0                  localnet/24           anywhere              any
       #





  33..11..44..1111..  SSeettttiinngg PPoolliiccyy

  We glossed over what happens when a packet hits the end of a built-in
  chain when we discussed how a packet walks through chains in
  ``Specifying a Target'' above.  In this case, the `policy' of the
  chain determines the fate of the packet.  Only built-in chains
  (`input', `output' and `forward') have policies, because if a packet
  falls off the end of a user-defined chain, traversal resumes at the
  previous chain.


  The policy can be any of the first four special targets: `ACCEPT',
  `DENY', `REJECT' or `MASQ'.  `MASQ' is only valid for the `forward'
  chain.



  It is also important to note that a `RETURN' target in a rule in one
  of the built-in chains is useful to explicitly target the chain policy
  when a packet matches a rule.


  33..11..55..  OOppeerraattiioonnss oonn MMaassqquueerraaddiinngg

  There are several parameters you can tweak for IP Masquerading.  They
  are bundled with `ipchains' because it's not worth writing a separate
  tool for them (although this will change).


  The IP Masquerading command is `-M', and it can be combined with `-L'
  to list currently masqueraded connections, or `-S' to set the
  masquerading parameters.


  The `-L' command can be accompanied by `-n' (show numbers instead of
  hostnames and port names) or `-v' (show deltas in sequence numbers for
  masqueraded connection, just in case you care).


  The `-S' command should be followed by three timeout values, each in
  seconds: for TCP sessions, for TCP sessions after a FIN packet, and
  for UDP packets.  If you don't want to change one of these values,
  simply give a value of `0'.


  The default values are listed in `/usr/include/net/ip_masq.h',
  currently 15 minutes, 2 minutes and 5 minutes respectively.


  The most common value to change is the first one, for FTP (see ``FTP
  Nightmares'' below).


  33..11..66..  CChheecckkiinngg aa PPaacckkeett

  Sometimes you want to see what happens when a certain packet enters
  your machine, such as for debugging your firewall chains.  `ipchains'
  has the `-C' command to allow this, using the exact same routines that
  the kernel uses to diagnose real packets.


  You specify which chain to test the packet on by following the `-C'
  argument with its name.  Whereas the kernel always starts traversing
  on the `input', `output' or `forward' chains, you are allowed to begin
  traversing on any chain for testing purposes.


  The details of the `packet' are specified using the same syntax used
  to specify firewall rules.  In particular, a protocol (`-p'), source
  address (`-s'), destination address (`-d') and interface (`-i') are
  compulsory.  If the protocol is TCP or UDP, then a single source and a
  single destination port must be specified, and a ICMP type and code
  must be specified for the ICMP protocol (unless the `-f' flag is
  specified to indicate a fragment rule, in which case these options are
  illegal).


  If the protocol is TCP (and the `-f' flag is not specified), the `-y'
  flag may be specified, to indicate that the test packet should have
  the SYN bit set.



  Here is an example of testing a TCP SYN packet from 192.168.1.1 port
  60000 to 192.168.1.2 port www, entering the `input' chain.  (This is a
  classic incoming WWW connection initiation):



       # ipchains -C input -p tcp -y -s 192.168.1.1 60000 -d 192.168.1.2 www
       packet accepted
       #





  33..11..77..  MMuullttiippllee RRuulleess aatt OOnnccee aanndd WWaattcchhiinngg WWhhaatt HHaappppeennss

  Sometimes a single command line can result in multiple rules being
  effected.  This is done in two ways.  Firstly, if you specify a
  hostname which resolves (using DNS) to multiple IP addresses,
  `ipchains' will act as if you had typed multiple commands with each
  combination of addresses.


  So if the hostname `www.foo.com' resolves to three IP addresses, and
  the hostname `www.bar.com' resolves to two IP addresses, then the
  command `ipchains -A input -j reject -s www.bar.com -d www.foo.com'
  would append six rules to the `input' chain.


  The other way to have `ipchains' perform multiple actions is to use
  the bidirectional flag (`-b').  This flag makes `ipchains' behave as
  if you had typed the command twice, the second time with the `-s' and
  `-d' arguments reversed.  So, to avoid forwarding either to or from
  192.168.1.1, you could do the following:



       # ipchains -b -A forward -j reject -s 192.168.1.1
       #





  Personally, I don't like the `-b' option much; if you want
  convenience, see ``Using ipchains-save'' below.


  The -b option can be used with the insert (`-I'), delete (`-D') (but
  not the variation which takes a rule number), append (`-A') and check
  (`-C') commands.


  Another useful flag is `-v' (verbose) which prints out exactly what
  `ipchains' is doing with your commands.  This is useful if you are
  dealing with commands that may effect multiple rules.  For example,
  here we check the behaviour of fragments between 192.168.1.1 and
  192.168.1.2.








  # ipchains -v -b -C input -p tcp -f -s 192.168.1.1 -d 192.168.1.2 -i lo
    tcp opt   ---f- tos 0xFF 0x00  via lo    192.168.1.1  -> 192.168.1.2    * ->   *
  packet accepted
    tcp opt   ---f- tos 0xFF 0x00  via lo    192.168.1.2  -> 192.168.1.1    * ->   *
  packet accepted
  #





  33..22..  UUsseeffuull EExxaammpplleess

  I have a dialup PPP connection (`-i ppp0').  I grab news (`-p TCP -s
  news.virtual.net.au nntp') and mail (`-p TCP -s mail.virtual.net.au
  pop-3') every time I dial up.  I use Debian's ftp method to update my
  machine regularly (`-p TCP -s ftp.debian.org ftp-data').  I surf the
  web through my ISP's proxy while this is going on (`-p TCP -d
  proxy.virtual.net.au 8080'), but hate the ads from doubleclick.net on
  the Dilbert Archive (`-p TCP -y -d 199.95.207.0/24' & `-p TCP -y -s
  199.95.208.0/24').


  I don't mind people trying to ftp to my machine while I'm online (`-p
  TCP -d $LOCALIP ftp'), but don't want anyone outside pretending to
  have an IP address of my internal network (`-s 192.168.1.0/24').


  This setup is fairly simple, because there are currently no other
  boxes on my internal network.


  I don't want any local process (ie. Netscape, Gzilla etc.) to connect
  to doubleclick.net:



       # ipchains -A input -d 199.95.207.0/24 -j REJECT
       # ipchains -A input -d 199.95.208.0/24 -j REJECT
       #




  Note that if I cared, I could specify `-i lo' as locally-generated
  packets traversing the `input' chain have their interface set to `lo'.


  Now I want to set priorities on various outgoing packets (there isn't
  much point in doing it on incoming packets).  Since I have a fair
  number of these rules, it makes sense to put them all in a single
  chain, called `ppp-out'.



       # ipchains -N ppp-out
       # ipchains -A output -i ppp0 -j ppp-out
       #





  Minimum delay for web traffic & telnet.


       # ipchains -A ppp-out -p TCP -d proxy.virtual.net.au 8080 -t 0x00 0x10
       # ipchains -A ppp-out -p TCP -d 0.0.0.0 telnet -t 0x00 0x10
       #





  Low priority for ftp data, nntp, pop-3:



       # ipchains -A ppp-out -p TCP -d 0.0.0.0/0 ftp-data -t 0x00 0x02
       # ipchains -A ppp-out -p TCP -d 0.0.0.0/0 nntp -t 0x00 0x02
       # ipchains -A ppp-out -p TCP -d 0.0.0.0/0 pop-3 -t 0x00 0x02
       #





  There are a few restrictions on packets coming in the ppp0 interface:
  let's create a chain called `ppp-in':



       # ipchains -N ppp-in
       # ipchains -A input -i ppp0 -j ppp-in
       #





  Now, no packets coming in ppp0 should be claiming a source address of
  192.168.1.*, so we log and deny them:



       # ipchains -A ppp-in -s 192.168.1.0/24 -l -j DENY
       #





  I allow connections in for DNS (I forward all requests to
  `203.29.16.1', so I expect DNS TCP replies from them only), ftp, and
  return ftp-data only (which should only be going to a port above
  1023).



       # ipchains -A ppp-in -p TCP -s 203.29.16.1 -d $LOCALIP dns -j ACCEPT
       # ipchains -A ppp-in -p TCP -s 0.0.0.0/0 ftp-data -d $LOCALIP 1024: -j ACCEPT
       # ipchains -A ppp-in -p TCP -d $LOCALIP ftp -j ACCEPT
       #





  Finally, other locally-generated packets are OK:



  # ipchains -A input -i lo -j ACCEPT
  #





  Now, my default policy on the `input' chain is DENY, so everything
  else gets rejected:



       # ipchains -P input DENY
       #





  NOTE: I wouldn't set up my chains in this order, as packets might get
  through while I'm setting up.  Safest is usually to set the policy to
  DENY first, then insert the rules.  Of course, if your rules require
  DNS lookups to resolve hostnames, you could be in trouble.


  33..22..11..  UUssiinngg ````iippcchhaaiinnss--ssaavvee''''

  Setting up firewall chains just the way you want them, and then trying
  to remember the commands you used so you can do them next time is a
  pain.


  So, `ipchains-save' is a script which reads your current chains setup
  and saves it to a file.  For the moment I'll keep you in suspense with
  regards to what `ipchains-restore' does.


  `ipchains-save' can save a single chain, or all chains (if no chain
  name is specified).  The only option currently permitted is `-v' which
  prints the rules (to stderr) as they are saved.  The policy of the
  chain is also saved for `input', `output' and `forward' chains.



       $ ipchains-save > my_firewall
       Saving `input'.
       Saving `output'.
       Saving `forward'.
       Saving `ppp-in'.
       Saving `ppp-out'.
       $





  33..22..22..  UUssiinngg ````iippcchhaaiinnss--rreessttoorree''''

  `ipchains-restore' restores chains as saved with `ipchains-save'.  It
  can take two options: `-v' which describes each rule as it is added,
  and `-f' which forces flushing of user-defined chains if they exist,
  as described below.


  If a user-defined chain is found in the input, `ipchains-restore'
  checks if that chain already exists.  If it does, then you will be
  prompted whether the chains should be flushed (cleared of all rules)
  or whether restoring this chain should be skipped.  If you specified
  `-f' on the command line, you will not be prompted; the chain will be
  flushed.


  You must be root to run this script; it uses `ipchains' to attempt to
  restore the rules.


  For example:



       # ipchains-restore < my_firewall
       Restoring `input'.
       Restoring `output'.
       Restoring `forward'.
       Restoring `ppp-in'.
       Chain `ppp-in' already exists. Skip or flush? [S/f]? s
       Skipping `ppp-in'.
       Restoring `ppp-out'.
       Chain `ppp-out' already exists. Skip or flush? [S/f]? f
       Flushing `ppp-out'.
       #





  44..  MMiisscceellllaanneeoouuss

  This section contains all the information and FAQs that I couldn't fit
  inside the structure above.


  44..11..  HHooww ttoo OOrrggaanniissee YYoouurr FFiirreewwaallll RRuulleess

  This question requires some thought.  You can try to organise them to
  optimize speed (minimize the number of rule-checks for the most common
  packets) or to increase managability.


  If you have an intermittent link, say a PPP link, you might want to
  set the first rule in the input chain to be set to `-i ppp0 -j DENY'
  at boot time, then have something like this in your `ip-up' script:



       # Re-create the `ppp-in' chain.
       ipchains-restore -f < ppp-in.firewall

       # Replace DENY rule with jump to ppp-handling chain.
       ipchains -R input 1 -i ppp0 -j ppp-in





  Your ip-down script would look like:



       ipchains -R input 1 -i ppp0 -j DENY


  44..22..  WWhhaatt NNOOTT ttoo FFiilltteerr OOuutt

  There are some things you should be aware of before you start
  filtering out everything you don't want.


  44..22..11..  IICCMMPP PPaacckkeettss

  ICMP packets are used (among other things) to indicate failure for
  other protocols (such as TCP and UDP).  `destination-unreachable'
  packets in particular.  Blocking these packets means that you will
  never get `Host unreachable' or `No route to host' errors; any
  connections will just wait for a reply that never comes.  This is
  irritating, but rarely fatal.


  A worse problem is the role of ICMP packets in MTU discovery.  All
  good TCP implementations (Linux included) use MTU discovery to try to
  figure out what the largest packet that can get to a destination
  without being fragmented (fragmentation slows performance, especially
  when occasional fragments are lost).  MTU discovery works by sending
  packets with the "Don't Fragment" bit set, and then sending smaller
  packets if it gets an ICMP packet indicating "Fragmentation needed but
  DF set" (`fragmentation-needed').  This is a type of `destination-
  unreachable' packet, and if it is never received, the local host will
  not reduce MTU, and performance will be abysmal or non-existant.


  44..22..22..  DDNNSS RReepplliieess

  You might think that you can block any incoming TCP connections, but
  there are two cases where this will break things, and the first is
  DNS.  Your machine uses DNS to turn hostnames into IP addresses.
  Normally DNS uses UDP, however, if the reply is large, it uses TCP to
  reply.  Blocking these connections will make DNS unreliable.


  If your DNS queries are always directed at the same external source
  (either directly by using the `nameserver' line in /etc/resolv.conf,
  or by using a caching nameserver in forward mode), then you need only
  allow TCP connections to port `domain' from that machine.


  44..22..33..  FFTTPP NNiigghhttmmaarreess

  The other classic problem is FTP.  FTP has two "modes"; the
  traditional one is called `active mode' and the more recent one is
  called `passive mode'.  Web browsers usually default to passive mode,
  but command-line ftp programs usually default to active mode.


  In active mode, when the remote end wants to send a file (or even the
  results of an `ls' or `dir' command) it tries to open a TCP connection
  to the local machine.  This means you can't filter out these TCP
  connections without breaking active FTP.


  If you have the option of using passive mode, then fine; passive mode
  makes data connections from client to server, even for incoming data.
  Otherwise, it is recommended that you only allow TCP connections to
  ports above 1024 and not between 6000 and 6010 (6000 is used for X-
  Windows).




  44..33..  FFiilltteerriinngg oouutt PPiinngg ooff DDeeaatthh

  Linux boxes are now immune to the famous Ping of Death, which involves
  sending an illegally-large ICMP packet which overflows buffers in the
  TCP stack on the receiver and causes havoc.


  If you are protecting boxes which might be vulnerable, you can simply
  block ICMP fragments.  Normal ICMP packets aren't large enough to
  require fragmentation, so you won't break anything except big pings.
  I have heard (unconfirmed) reports that some systems required only the
  last fragment of an oversize ICMP packet to corrupt them, so blocking
  only the first fragment is not recommended.


  44..44..  FFiilltteerriinngg oouutt TTeeaarrddrroopp aanndd BBoonnkk

  Teardrop and Bonk are two attacks (mainly against Microsoft Windows NT
  machines) which rely on overlapping fragments.  Having your Linux
  router do defragmentation, or disallowing all fragments to your
  vulnerable machines are the other options.


  44..55..  FFiilltteerriinngg oouutt FFrraaggmmeenntt BBoommbbss

  Some less-reliable TCP stacks are said to have problems dealing with
  large numbers of fragments of packets when they don't receive all the
  fragments.  Linux does not have this problem.  You can filter out
  fragments (which might break legitimate uses) or compile your kernel
  with `IP: always defragment' set to `Y' (only if your Linux box is the
  only possible route for these packets).


  44..66..  CChhaannggiinngg FFiirreewwaallll RRuulleess

  There are some timing issues involved in altering firewall rules.  If
  you are not careful, you can let packets through while you are half-
  way through your changes.  A simplistic approach is to do the
  following:



       # ipchains -I input 1 -j DENY
       # ipchains -I output 1 -j DENY
       # ipchains -I forward 1 -j DENY

       ... make changes ...

       # ipchains -D input 1
       # ipchains -D output 1
       # ipchains -D forward 1
       #




  This drops all packets for the duration of the changes.


  If you changes are restricted to a single chain, you might want to
  create a new chain with the new rules, and then replace (`-R') the
  rule that pointed to the old chain with one that points to the new
  chain: then you can delete the old chain.  This replacement will occur
  atomically.


  44..77..  AAddvvaanncceedd PPrroojjeeccttss

  There is a userspace library I have written which is included with the
  source distribution called `libfw'.  It uses the ability of IP Chains
  1.3 and above to copy a packet to userspace (using the
  IP_FIREWALL_NETLINK config option).


  Things such as `stateful inspection' (I prefer the term dynamic
  firewalling) can be implemented in userspace using this library.
  Other nifty ideas include controlling packets on a per-user basis by
  doing a lookup in a userspace daemon.  This should be pretty easy.


  The `mark' capability of the firewalls is underutilised: it could
  easily be used to represent a priority for the Quality of Service
  code, which would make it simple to control packet priorities.


  44..88..  FFuuttuurree EEnnhhaanncceemmeennttss

  In the future I want to put all the firewall controls under
  /proc/sys/net/ipv4.  This would make manipulation using scripts
  easier, and make things cleaner generally.


  I would really a good way to reinject packets into a particular chain
  from userspace.  This would make the libfw design simpler.


  55..  AAppppeennddiixx -- DDiiffffeerreenncceess bbeettwweeeenn iippcchhaaiinnss aanndd iippffwwaaddmm

  Some of these changes are a result of kernel changes, and some a
  result of ipchains being different from ipfwadm.



  1. Many arguments have been remapped: capitals now indicates a
     command, and lower case now indicates an option.

  2. Arbitrary chains are supported, so even built-in chains have full
     names instead of flags (eg. `input' instead of `-I').

  3. The `-k' option has vanished: use `! -y'.

  4. The `-b' option actually inserts/appends/deletes two rules, rather
     than a single `bidirectional' rule.

  5. The `-b' option can be passed to `-C' to do two checks (one in each
     direction).

  6. The `-x' option to `-l' has been replaced by `-v'.

  7. Multiple source ports are not supported anymore.  Hopefully being
     able to negate the port range will somewhat make up for that.

  8. Interfaces can only be specified by name (not address).  The old
     semantics got silently changed in the 2.1 kernel series anyway.

  9. Fragments are examined, not automatically allowed through.

  10.
     Explicit accounting chains have been done away with.

  11.
     Arbitrary protocols over IP are supported.
  12.
     The old behaviour of SYN and ACK matching (which was previously
     ignored for non-TCP packets) has changed; the SYN option is not
     valid for non-TCP-specific rules.

  13.
     Counters are now 64-bit on x86, not 32-bit.

  14.
     Inverse options are now supported.

  15.
     ICMP codes are now supported.

  16.
     Wildcard interfaces are now supported.

  17.
     TOS manipulations are now sanity-checked: the old kernel code would
     silently stop you from (illegally) manipulating the `Must Be Zero'
     TOS bit; ipchains now returns an error if you try, as well as for
     other illegal cases.


  55..11..  QQuuiicckk--RReeffeerreennccee TTaabbllee

  [ Mainly, command arguments are UPPER CASE, and option arguments are
  lower case ]


  One thing to note, masquerading is specified by `-j MASQ'; it is
  completely different from `-j ACCEPT', and not treated as merely a
  side-effect, unlike ipfwadm does.

































  ================================================================
  | ipfwadm      | ipchains              | Notes
  ----------------------------------------------------------------
  | -A [both]    | -N acct               | Create an `acct' chain
  |              |& -I 1 input -j acct   | and have output and input
  |              |& -I 1 output -j acct  | packets traverse it.
  |              |& acct                 |
  ----------------------------------------------------------------
  | -A in        | input                 | A rule with no target
  ----------------------------------------------------------------
  | -A out       | output                | A rule with no target
  ----------------------------------------------------------------
  | -F           | forward               | Use this as [chain].
  ----------------------------------------------------------------
  | -I           | input                 | Use this as [chain].
  ----------------------------------------------------------------
  | -O           | output                | Use this as [chain].
  ----------------------------------------------------------------
  | -M -l        | -M -L                 |
  ----------------------------------------------------------------
  | -M -s        | -M -S                 |
  ----------------------------------------------------------------
  | -a policy    | -A [chain] -j POLICY  | (but see -r and -m).
  ----------------------------------------------------------------
  | -d policy    | -D [chain] -j POLICY  | (but see -r and -m).
  ----------------------------------------------------------------
  | -i policy    | -I 1 [chain] -j POLICY| (but see -r and -m).
  ----------------------------------------------------------------
  | -l           | -L                    |
  ----------------------------------------------------------------
  | -z           | -Z                    |
  ----------------------------------------------------------------
  | -f           | -F                    |
  ----------------------------------------------------------------
  | -p           | -P                    |
  ----------------------------------------------------------------
  | -c           | -C                    |
  ----------------------------------------------------------------
  | -P           | -p                    |
  ----------------------------------------------------------------
  | -S           | -s                    | Only takes one port or
  |              |                       | range, not multiples.
  ----------------------------------------------------------------
  | -D           | -d                    | Only takes one port or
  |              |                       | range, not multiples.
  ----------------------------------------------------------------
  | -V           | <none>                | Use -i [name].
  ----------------------------------------------------------------
  | -W           | -i                    |
  ----------------------------------------------------------------
  | -b           | -b                    | Now actually makes 2 rules.
  ----------------------------------------------------------------
  | -e           | -v                    |
  ----------------------------------------------------------------
  | -k           | ! -y                  | Doesn't work unless
  |              |                       | -p tcp also specified.
  ----------------------------------------------------------------
  | -m           | -j MASQ               |
  ----------------------------------------------------------------
  | -n           | -n                    |
  ----------------------------------------------------------------
  | -o           | -l                    |
  ----------------------------------------------------------------
  | -r [redirpt] | -j REDIR [redirpt]    |
  ----------------------------------------------------------------
  | -t           | -t                    |
  ----------------------------------------------------------------
  | -v           | -v                    |
  ----------------------------------------------------------------
  | -x           | -x                    |
  ----------------------------------------------------------------
  | -y           | -y                    | Doesn't work unless
  |              |                       | -p tcp also specified.
  ----------------------------------------------------------------




  55..22..  EExxaammpplleess ooff ttrraannssllaatteedd iippffwwaaddmm ccoommmmaannddss

  Old command: ipfwadm -F  -p deny

  New command: ipchains -P forward DENY


  Old command: ipfwadm -F -a m -S 192.168.0.0/24 -D 0.0.0.0/0

  New command: ipchains -A forward -j MASQ -s 192.168.0.0/24 -d
  0.0.0.0/0


  Old command: ipfwadm -I -a accept -V 10.1.2.1 -S 10.0.0.0/8 -D
  0.0.0.0/0

  New command: ipchains -A input -j ACCEPT -i eth0 -s 10.0.0.0/8 -d
  0.0.0.0/0

  (Note that there is no equivalent for specifying interfaces by
  address: use the interface name.  On this machine, 10.1.2.1
  corresponds to eth0).


  66..  AAppppeennddiixx -- UUssiinngg tthhee ``iippffwwaaddmm--wwrraappppeerr'' ssccrriipptt

  The `ipfwadm-wrapper' shell script should be a plug-in replacement of
  ipfwadm for backwards compatibility with ipfwadm 2.3a.


  The only feature it can't really handle is the `-V' option.  When this
  is used, a warning is given.  If the `-W' option is also used, the
  `-V' option is ignored.  Otherwise, the script tries to find the
  interface name associated with that address, using `ifconfig'.  If
  that fails (such as for an interface which is down) then it will exit
  with an error message.


  This warning can be suppressed by either changing the `-V' to a `-W',
  or directing the standard output of the script to /dev/null.


  If you should find any mistakes in this script, or any changes between
  the real ipfwadm and this script, PLEASE report a bug to me: send an
  EMail to Paul.Russell@rustcorp.com.au with "BUG-REPORT" in the
  subject.  Please list you old version of ipfwadm (`ipfwadm -h'), your
  version of ipchains (`ipchains --version'), the version of the ipfwadm
  wrapper script (`ipfwadm-wrapper --version').  Also send the output of
  `ipchains-save'.  Thanks in advance.


  Mix ipchains with this ipfwadm-wrapper script at your own peril.


  77..  AAppppeennddiixx -- TThhaannkkss

  Many thanks have to go to Michael Neuling, who wrote the first
  releasable cut of the Generic IP Chains code while working for me.
  Public apologies for nixing his result-caching idea, which Alan Cox
  later proposed and I have finally begun implementing, having seen the
  error of my ways.


  Thanks to Alan Cox for his 24-hour EMail tech support, and
  encouragement.


  Thanks to all the authors of the ipfw and ipfwadm code, especially Jos
  Vos.  Standing on the shoulders of giants and all that...  This
  applies to Linus Torvalds and all the kernel and userspace hackers as
  well.


  Thanks to the diligent beta testers and bughunters, especially:

     JJoorrddaann MMeennddeellssoonn
        ICMP code suggestion.

     SShhaaww CCaarrrruutthheerrss
        For various ipchains and ipfwadm-wrapper bugfixes.

     KKeevviinn MMoouullee
        For a patch for glibc.

     DDrr.. LLiivviiuu DDaaiiaa
        For documentation fixes and printk fix.

     HHeellmmuutt AAddaammss
        For fixing a race condition in v. large chains.

     FFrraanncckk SSiiccaarrdd
        For masquerading listing fix.

     KKeevviinn LLiittttlleejjoohhnn
        For ipchains-save bugfix with destination ports.

     MMaatttt KKeemmnneerr
        For more documentation fixes.

     JJoohhnn DD.. HHaarrddiinn
        For `ipchains -X' suggestion.

     AAlleexxeeyy KKuuzznneettssoovv
        For noticing a typo which stop marks being initialised.

     RRiiccaarrddoo KKuussttnneerr
        For fixing my leftover debug messages in 2.0.33.













