README file for ip_resend-0.3 pre

Purpose:
========

A demand dial accelerator for ppp links with dynamic ip addresses.

Description in Brief
====================

The response to the first packet sent through a dynamic-ip demand dial
ppp connection is usually lost. The upper layers usually recover from
such loss only after a noticeable delay. ip_resend eliminates such delays
by resending the first packet with adjusted ip-addresses as soon as the
link is operational.

ip_resend operates entirely from user space (no kernel patch is needed).


CHANGES for Version 0.3

- marked beta. I dont think that any further features are missing.
  And several tests have proved that it actually works as expected.
- Added instructions for iptables-based (Linux 2.4.x) masquerading routers.
- Added instructions for testing
- added lsm entry

CHANGES for Version 0.2

- New (incompatible) command line options for finer grained control.
  You'll need to re-edit your boot and ppp scripts if you have
  already installed the 0.1 version.
- Name of Unix domain communication socket is now determined
  automatically from the interface name unless explicitly specified.
- The snoop interface can be different from the outgoing interface now.
  This allows ip_resend to be used with diald proxy interfaces.  
- The `stop' and `term' message are now explicitly recognized by ip_resend.
- TTL of re-sent packet is adjusted.


Synopsis
========

ip_resend  -o OUTGOING_INTERFACE [-s SNOOP_INTERFACE] [-c COMMUNICATION_SOCKET]
              [-w WAKEUP_WAIT_MAX] [-{r|R} RESPONSE_WAIT_MAX] [-d DEBUG_LEVEL]

ip_resend_wakeup  -m WAKEUP_MESSAGE {-d NETWORK_INTERFACE | -c PF_UNIX_PATH}


Description
===========

ip_resend snoops at a Linux network interface as specified by its command
line options for outgoing packets. As soon as an outgoing IP packet is
detected, ip_resend reads that packet and stores it internally.

ip_resend then waits until an ip_resend_wakeup command tells
it to proceed. An upper limit for the time to wait can be specified
by the `-w' option. The default value is currently 10 seconds.

ip_resend_wakeup expects an ip-address in dotted decimal notation as
as the `-m' option's argument. This ip-address is sent as a
message to the waiting ip_resend process.

After ip_resend has received the new ip-address, the source ip-address
of the snooped packet is replaced by the new ip-address and the modified
packet is resent.

ip_resend then waits for the first incoming (response) IP packet.
It replaces the destination IP address of the response packet by the
old network interface address. The modified response packet is then
re-sent to the local host via the local loopback network interface.
An upper limit for the time to wait can be specified by the `-r' option.
The default value is currently 10 seconds. 

Communication between ip_resend and ip_resend_wakeup is done by means
of a PF_UNIX domain socket which can be specified by the `-c' option.
The co-operating ip_resend and ip_resend_wakeup processes must use
the same communication socket. If no `-c' option is present, the name
of the communication socket is derived from the outgoing interface name
(`-o' option) by prepending the directory name `/var/ip_resend/'.


What's that for?    How Does it work?
=====================================

These programs aim at solving timeout problems related to
demand-dialing ppp links with dynamic ip-address assignment.

Demand dialing is usually triggered by an outgoing packet that
is routed through this interface. The packet which triggered dialing is
usually sent out as soon as the link is up. However, if the ip address
of the interface changed due to dynamic address assignment, the
sent packet still carries the old source IP address. As a result, the
receiver of that packet will reply to the old sender address. Thus,
the reply will never arrive at the sender.


The Linux kernel contains some hacks to work around such problems.
E.g. there is the ip_dynaddr feature which can be enabled by means of
/proc/sys/net/ipv4/ip_dynaddr. However, this only works with
tcp sockets. Usually, the first packet (which triggers dialing) is
a DNS lookup on top of UDP -- ip_dynaddr does not help here. Thus, the
DNS request will time out and needs to be repeated. This can cause
noticeable delays.

Now, ip_resend comes in. As soon as the connection is up and everything
in the kernel (e.g. network interface address, ip-masquerading) is
adjusted to the newly assigned ip-address, the source address of the
packet is changed to the new interface address and the packet is sent
out again. As the source address of the re-sent packet now bears the
proper sender address, the reply to this resent packet will be routed
correctly back to us.

However, if the socket (where the dial-triggering first packet originated
from) was bound to the old interface address, this does not help yet.
Although the response packet will correctly arrive at our host now, the
socket where the process expects the response is still bound to the old
interface address. Thus, the process still would not receive the response.

But ip_resend supports waiting for the response packet itself. If the
response arrives at the host, a copy of it gets delivered to ip_resend.
ip_resend then replaces the destination address of the response packet
by the old interface address. It then resends that modified packet back to
its own host by means of the local loopback interface.

Now, that packet carries the right (old interfaces) destination
address and the socket expecting the reply will receive it.

In brief, ip_resent is a one-time NAT (Network Address Translation)
which is performed completely from user space. Only the first outgoing
and the first incoming packet is translated. IP, TCP and UDP header
checksums are also adjusted.

The problem is well-known inside the isdn4linux community for years, but
it is a principal problem affecting any kind of demand dial link with
dynamic address assignment. E.g. isdn links controlled by ipppd,
pppd-controlled demand dial links (async, pppoe, adsl, ...) 
and diald-controlled ppp links all suffer from that problem. But async
link setup is very slow, the modem training phase might easily last
for a half minute. If you use async ppp and telnet to a remote host, you
probably wont realize the difference between a login prompt appearing
32 seconds or 35 seconds after hitting RETURN. But on an isdn link, the
difference between 2 seconds and 5 seconds is very noticeable.

As other kinds of fast-connect ppp carriers (adsl,pppoe) are getting common
now, the problem now also gains attention outside the isdn4linux community.
The good news is that ip_resend is not isdn-specific. It should work with
any kind of demand-dial link that uses dynamic IP-address assignment.

ip_resend is Linux-specific, it uses low level PF_PACKET sockets.
It should be possible to port it to other Unix-like OS which provide
for a similar interface. If you intend to do so, you might consider to
use libpcap.



How to build
============

ip_resend should work with any 2.2.x or 2.4.x kernel. 2.0.x and
below won't work. However, I've tested with 2.4.0-test9 only.

Compile the package by typing `make'. If this was successful, login as 
root and type

make test

This will execute ip_resend and ping using the local loopback
interface. Wait until ping reports to have received three packets.
It is not possible to fully test ip_resend on the local loopback
interface, but you should see that it basically works.

If `make test' indicates no problems, type

make install


How to use
==========

After successful compilation and installation of the binaries, you need
to edit certain configuration files. Typically, these will be

- /etc/ppp/ip-down
- /etc/ppp/ip-up
- /etc/rc.d/* (this might differ depending on your distribution)

ip_resend needs to be restarted when the connection goes down while
the interface is in demand-dial mode. This is usually done from
the /etc/ppp/ip-down script.

ip_resend_wakeup must be executed after the demand dialing connection
went up and the network interface is configured for the new IP-address.
This is usually done from the /etc/ppp/ip-up script.

ip_resend must also be started initially before the first ppp connection
is set up. This is typically either done at boot time or by explicit
user intervention. The script file which starts [i]pppd at boot
time typically resides in the directory /etc/rc.d, /etc/rc.d/init.d or
/sbin/init.d (depends on Linux distribution). Try a `grep pppd /etc/rc.d/*'
in order to locate such files. If [i]pppd is started manually by a script,
locate that and remember that script file.

This example assumes that the ppp network interface with dynamic address
assignment is ippp0. If the network interface is different, replace 'ippp0'
by the name of your ppp interface.


In your boot-up or ppp-initialization script (where the demand dial
[i]pppd is started), you should add a line

	ip_resend -o ippp0 &

after the line where [i]pppd is started.


At the very end of your /etc/ppp/ip-up script, insert a command
	
	if [ X$1 = Xippp0 ]; then
		ip_resend_wakeup -m $4 -o $1
	fi

The latter tells ip_resend about the new interface address (which is
passed to ip-up in $4) and triggers to resend the packet, replacing
its old source address by the new interface address.


At the very end of your /etc/ppp/ip-down, insert a command

	if [ X$1 = Xippp0 ]; then
		exec ip_resend -o $1
	fi

This will restart a new ip_resend after the connection went down.


As /etc/ppp/ip-up and /etc/ppp/ip-down are not attached to a terminal,
consider appending, e.g., "> /dev/tty2 2>&1" to all "ip_resend" and
"ip_resend_wakeup" commands above such that you can watch ip_resend's
error and debug messages on virtual terminal 2.

If done with the installation, you can test like this:

Choose an ip address for a host that is well-reachable via your
provider's network (like the ip-address of the provider's name server).
E.g. for ARCOR internet, the address of a local nameserver
is 145.253.2.11. Type

	time ping -c 1 145.253.2.11

You might also test for DNS-resolver triggered demand dialup, e.g.

	time ping -c 1 

The basic principle looks simple, but there are some possible caveats:
ip_resend and ip_resend_wakeup might get out of sync or multiple
simultaneous ip_resend tasks might be started if certain race or error
conditions occurred. ip_resend is prepared for this and
aims at recovering from such states on its own. The worst case that
should actually occur is a demand dialing event which is not accelerated
by ip_resent.



What to know about ip_resend interactions with other software and OS features?
==============================================================================


That will depend on your host configuration. I can envision 4 different
demand dial combinations:

- demand dialing can be either initiated by  diald  or directly by the
  ppp subsystem (like  isdn demand dial  ippp interface or like async
  ppp controlled by  demand dial pppd)
- Your computer is either a stand-alone machine (single host) or
  your computer should be able to route traffic between your LAN
  and the global Internet through the demand dial ppp link
  (masquerading router).


Single Host, standard  pppd / ipppd  demand dialer
--------------------------------------------------

Basically, the installation instructions as described above are sufficient.
ip_resend will do a good job for accelerating DNS-lookup triggered
demand dial connections.

In order to prevent hangs caused by tcp-syn triggered demand dialing,
it is recommended to additionally enable the ip_dynaddr feature by

	echo 2 > /proc/sys/net/ipv4/ip_dynaddr


Single Host, demand dialing controlled by diald
-----------------------------------------------

If you are using ip_resend with diald, ip_resend needs to snoop on
diald's proxy interface instead of the outgoing interface. In that
case, additionally supply the proxy interface by means of the '-s'
option. e.g., if the proxy interface is sl0, start ip_resend like this

	ip_resend -o ippp0 -s sl0

You also might additionally want to enable ip_dynaddr.
(ip_resend with diald is untested, but no problems are expected).
 

Masquerading router, standard  pppd / ipppd  demand dialer
----------------------------------------------------------

If you intend to use the dynamic ppp host as a router from
your LAN to the global Internet, you will need to set up ip masquerading.
IP-masquerading is different in 2.2.x and 2.4.0 kernels. I've only
tested for 2.4.0 kernels, and the instructions are only valid for 2.4.0.

For 2.4.0 kernels, install ip_resend exactly as described for the
single host case above. If it works on the ppp host, enable
masquerading and routing by

    iptables -t nat -A POSTROUTING -o ippp0 -j MASQUERADE
    echo 1 > /proc/sys/net/ipv4/ip_forward

(This needs to be done only once, you can put the commands in a boot script
after you have verified that it works). That's all! After that, you should
be able to set up a low-delay ip connection from a host on your lan to
the outside internet.

ip_dynaddr can be enabled additionally (although I have not tested
whether this is really necessary for locally originating tcp connections).

2.4.x kernels discard all masquerading mapping as soon as the interface
address changes. As address change occurs only after the first packet
has passed through the masquerading module, the response to the first
packet will not be translated by the kernel. But ip_resend itself will
handle translating the response to the first packet gracefully, further
packets will be translated by the kernel's IP-masquerading module.


I don't know about other kernel version masquerading details. If your
kernel's masquerading will already translate the response to the first
packet, ip_resend might not need to translate it again.

If you are experienced in 2.2.x IP-masquerading, feel free to
try it and tell me what happened. You can inhibit that ip_resends
translates the response packet by using zero as the max waiting
time for the response (`-r 0'-option). (If you still want to be
notified when the response arrives, you can use `-R'-option, e.g.
`-R 10'. `-R' is like `-r' in that ip_resend waits up to the time
specified in the options argument. But when the response arrives,
ip_resend just exits, without translating the response packet.)

The latter will only work if masquerading's port-mapping does not
change when the interface address changes. Otherwise, ip_resend needs
to co-operate with ip-masquerading which is not yet supported. As
ip_resend has already proven to co-exist very peacefully with 2.4.x
masquerading, I don't have plans to look after this myself.


Masquerading router, controlled by diald
----------------------------------------

If you are setting up a masquerading router, you should consider
to use diald. diald supports very sophisticated control of
auto-dialing and its proxy-interface paradigm is the cleanest method
to control auto-dialing anyway. Diald already supports re-sending
the first packet for masquerading routers. It does not support
translating the packet as ip_resend does. But with masquerading this
is not necessary because the kernels masquerading code will do so
if you use a recent diald version available from
http://diald.sourceforge.net.

Thus, you won't need ip_resend for diald controlled masquerading routers.


Security Considerations.
========================

File permissions:
-----------------

ip_resend and ip_resend_wakeup communicate by means of Unix domain
sockets which are by default created in /var/ip_resend/. Ordinary
user must not be permitted to create files in that directory.

Firewalling
-----------

The packet re-sent by ip_resent as well as the response packet intercepted
by ip_resend bypass any system-internal firewall code. If this is a
concern, try to really understand what ip_resend and your firewall filters
do and decide whether you still want to use it.

Fortunately, these packets are not totally unaffected be the firewall filters: 
- The snooped outgoing packet has already been blessed by the firewall
  rules for the outgoing interface.
- The response packet which is re-inserted in the network input path
  has not yet passed any firewall code when it is processed by ip_resend.
  However, it will pass through the firewall code when ip_resend inserts
  it again in the local network input path.

But keep in mind that it is now coming in via the local loopback interface!

If your firewall rules depend on the interface, you should consider
to add additional rules corresponding to the local loopback interface.
Also keep in mind that ip_resend might not fully work if you have
enabled route verification on the loopback interface
(e.g. by means of /proc/sys/net/ipv4/conf/lo/rp_filter).

Really, only the firewall administrator can make the decision whether
it is acceptable to use ip_resend on such hosts! Dont blame me if it
breaks the security of your system!


Disclaimer
==========

ip_resend comes with absolutely NO WARRENTY. See the GNU General Public
License for details.



Bugs
====

The whole program is a BUG ;). The real problem is that the IP
protocol was never designed for dynamic address assignment. Thus,
using dynamic ip addresses is already a bug. Unfortunately,
dynamic address assignment is a fact of life and an unavoidable
work-around against IP address range limitation.

Thus, any method to work around dynamic address assignment problems
is necessarily ugly. ip_resend tries at least to isolate the ugly
stuff in a single user space program and keeps the kernel free of it.


Looping the modified response packet back to the own host
can leave (at least under 2.4.0-test9) kernel messages 

	ip_local_deliver: bad loopback skb: PRE_ROUTING_LOCAL_IN ...

in the syslog which can be ignored.


If the interface address did not change after dialing, ip_resend will
generate duplicate packets. However, this does not harm because protocols
above IP must be designed to cope with duplicate packets.


Have a lot of fun --  and fast ppp dial-up ;)




Henner


Please report bugs or send patches to

ip-resend-bugs@baty.hanse.de

