README file for ip_resend-0.4 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.4 - ip_resend now places itself in the background (contributed by Karsten Keil) - debug, status and error messages are now written to the syslog instead of stdout or stderr. - Fixed compilation problem caused by libc netpacket header file changes. CHANGES for Version 0.3 - marked beta. I donīt 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] [-D] 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 interfaceīs) 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 wonīt 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, this version is tested with 2.4.9 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 script file and remember its file name. 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 ip_resend -o $1 fi This will restart a new ip_resend after the connection went down. 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. As /etc/ppp/ip-up and /etc/ppp/ip-down are not attached to a terminal, ip_resend-0.4 and above now writes its error, status and debug messages to the syslog. It also places itself into the background such that it won't cause the ip-down script to hang until the connection becomes active again. If you want to start ip_resend manually from the command line (e.g. for debugging purpose), you can apply the -D option. With this option, ip_resend won't place itsself into the background and its syslog messages will be additionally written to stderr. If done with the ip_resend installation and ip-up/down modification, you can test like this: Choose an ip address for a host that is well-reachable via your provider's network. Usually, the the provider's name server should be such a well-reachable machine. (If not, you should consider changing provider). 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. Make sure that your /etc/resolve.conf actually has configured your provider's nameserver as the primary nameserver. And use a host name which is known by that nameserver itsself (no need for the providers nameservr to consult another nameserver for resolving the name). I guess it is reasonable to assume that the provider's main www server or www proxy qualify for this. Thus, with the arcor example, you could try time ping -c 1 www.arcor.de When this has finnished, the ppp link is fully operational. Thus, the user time reported by the `time' command is a good estimate for the `dialup latency' (connection set up, name server response time, one round trip delay) which effects general demand dial connections and might even serve to benchmark different providers. My experience was that dialup latency can vary significantly depending on the provider. And also with the same provider, there are statistically significant differences depending on the time of day. Best observed dialup latency on isdn was around 2 seconds. Worst results even significatly exceeded 10 seconds. As this exceeds ip_resend's default timeout values, ip_resend will have no effect unless the timeout values are also increased accordingly by means of the -w and -r options. But even with increased timeout values, the effect might no longer be noticed (unless explicitly measured) because the effect of a lost first packet (typically causing 5 seconds delay in DNS lookup) will no longer be signifcant. 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.x 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 neither tested nor thought about 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 optionīs 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 (IMHO) 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 kernel's 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! Don't 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 version 4 address range limitations. 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 for 2.4.x kernels) messages like 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