README file for ip_resend-0.2

CHANGES for Version 0.2

- New (incompatible) command line options for finer grained control.
  Youll 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.


Purpose:
========

To reduce connection-setup delays on demand dialing ppp links with dynamic IP
address assignment. No kernel patch is needed.



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 AF_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/'.


Whats 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 kernels 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 packet is sent out again.
The re-sent packet now bears the proper sender address such that 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) 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.


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

ip_resend should work with any 2.2.x or 2.4.x kernel. 2.0.x and
below won't work. However, Ive 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

After successful compilation and installation, 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 directly /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 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


The basic principle looks simple, but there are some hidden traps where
you could step into: 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.


ip_resent is currently only tested for single host scenarios. You might
additionally want to enable the ip_dynaddr feature for such scenarios.
But this is not necessary for ip_resend itself.

UNTESTED: 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.
This will require a slightly different operation from ip_resend. The first
outgoing packet still needs to be resent. The response packet does not
need translation from ip_resend because the kernels masquerading module
will already do so.

This 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. Also keep in mind that
2.2.x and 2.4.x masquerading implementations are very different.

However, if you are experienced in IP-masquerading, feel free to try it
anyway 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.)

Anyway, 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. 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.


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

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. I think it usually wont
matter, but only the firewall administrator can make that decision. 

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.


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
leaves (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
