Here's the gory details on why the IPPORTFW patch is not suffucient
to run a masqueraded FTP server, and how this additional patch fixes 
it.


BACKGROUND:

The FTP protocol uses two connections.  A session is begun by opening
a "control" connection on port 21 (standard).  This connection is
used to pass commands and responses between the server and client,
and remains open for the entire session.  When the client issues a
command that requires data to be transfered (a file get or put, or a
directory listing), a separate "data" connection is opened just to
transfer the data, and then closed again.

The FTP protocol is one of those that puts IP information in the data
portion of certain packets.  Specifically, the IP address and port
number for each data connection is passed via the control connection.
Normally, the client sends a PORT command to the server to tell it
what IP/port the client will be listening on for the data connection,
and the server opens the connection.  In Passive mode, the client
sends a PASV command to the server, and the server chooses the
IP/port and passes it to the client in its reply to the PASV command.
The client then opens the connection.

This raises two problems for IP Masquerade.  First, for the cases
where the masqueraded host sends the IP/port information and the
external host opens the connection, the incoming connection on an
arbitrary port can not be handled - there's no way for the
ipfwadm/ipchains rulesets to know what to do with it.  Second, even
for the cases where the data connection is opened by the masqueraded
side there is a timeout problem.  The data connection will be
properly masqueraded, but if it is a long transfer the masquerade
entry for the control connection can timeout and be deleted.  Then
when the data transfer is finished the control connection has been
broken and life is over.

So without help, ip_masq only supports masqueraded clients running in
PASV mode, and only if the data transfers are not too long.

Both of these problems are solved by the ip_masq_ftp module, an
app-specific "helper" module.  When the module is loaded, it
registers itself with the ip_masq code as a "helper" for port 21
connections (by default).  When the ip_masq code is setting up a new
connection for an outgoing packet destined for port 21, it binds the
ip_masq_ftp module to the connection.  Then all incoming and outgoing
packets on that connection are first passed to the module for
possible action.

The existing ip_ftp_masq module does two things: 

- it checks incoming packets for replies to outgoing PASV commands.
  If it sees one, it sets up a new masquerade entry for the outgoing
  data connection rather than letting the normal ip_masq logic set
  up the entry when the first data packet is sent.  It does this
  just so it can set a special pointer in the data connection entry
  pointing at the control connection entry.  The ip_masq code uses
  this pointer to reset the timeout for the control connection when
  there is activity on the data connection.  This prevents the
  control connection from being deleted during a long data transfer.

- it checks outgoing packets for PORT commands, which mean the
  masqueraded client is telling the external server to open a
  data connection.  If it sees one, it sets up a new masquerade
  entry as if the connection were being opened from the masq side,
  and re-writes the PORT command packet to specify the masq box's
  IP address and the selected masq port number.  That way the
  incoming data packet will look like a reply to a previous outgoing
  packet, and the ip_masq code will know what to do with it.  And of
  course the new entry for the data connection is linked to the
  control connection so it will be kept alive.


THE PROBLEM:

All of the above is peachy, and it means masqueraded clients can talk
to external servers in both normal (PORT) and PASV modes with no
problem.  What if you want to run a server on a masqueraded box?
Well, the first step is to apply the IPPORTFW patch (to 2.0.x
kernels) and use ipportfw to forward incoming connections to port 21
to the appropriate internal server.

BUT, the original two FTP masquerade problems are back, and the
ip_masq_ftp module is no help this time.  First, because it doesn't
get "bound" to the external client-internal server connections, so it
isn't given the opportunity to process the packets.  Second, because
even if it was bound in, it is not orthogonal - it looks for
client-to-server packets only in the outbound direction, and
vice-versa.

So without help, ip_masq+portfw only supports external clients
running in normal (PORT) mode, and only if the data transfers are not
too long.


THE SOLUTION:

To handle masqeraded servers, the ip_masq_ftp module needs to be
orthogonal.  It needs check for PORT commands and PASV responses in
both directions.  If it sees *either* in an outgoing packet, it needs
to set up a masquerade entry and re-write the packet, as it currently
does for PORT commands.  If it sees *either* in an incoming packet,
it needs to set up the masquerade entry for keep-alive purposes, as
it currently does for PASV replies.

Also, the kernel needs to be patched in two places to make sure the
ip_masq_ftp module gets called in the first place.  First, the
IPORTFW patch needs an extra line to bind any registered helper apps
for the port it is forwarding.  Second, ip_masq_app.c needs to check
for helper apps based on the *source* port if it fails to match on the
destination port.  Currently, it does this only if IPAUTOFW is
enabled.

So, my patch consists of two small kernel changes (for 2.0.36) and a
re-write of ip_masq_ftp.c.


WARNING:

This trivial patch makes the kernel orthogonal.  Masq helper apps
will be identified and invoked regardless of whether it is the client
or server that is being masqueraded.

But since ipmasq + masq_app was not originally intended to be
orthogonal, the various masq apps presumably have not been written to
be orthogonal either.  So they will not be expecting some of the
packet traffic they may now receive.  While I wouldn't expect it, it
is *possible* that this kernel patch may break existing masq helpers
for other protocols.  I wouldn't expect it because they should see
extra traffic only if you actually run a masqeraded server, but I
haven't actually analysed any of the other masq apps to make sure.

Certainly, for each protocol where you want to run a masqed server,
the corresponding helper app will probably need to be re-written as I
have done for ip_masq_ftp.c.
