How to forward port in user space using socat
I was asked to help setting up a kind of traffic redirection through VPN. In particular, the VPN server is Cisco VPN so the client should be Cisco VPN client too. Since the client is Ubuntu Edgy, it is very easy to install and run cvpnd
. Then I tried to forward a TCP port to another host on the same port using IPTables and DNAT. Unfortunately, it failed. Incoming TCP connection through this port always get "connection refused". I guess that the problem might involve the module cisco_ipsec
. This module may hook packet routing somewhere in the kernel so DNAT will not work correctly through its network interface. However, I don't have enough to investigate deeper for more detail since the service must be available tonight. In other words, I have 15 minutes left. So I decided to use port forwarding tool running on user space instead. After searching for a while, I found socat. socat looks like an extension of netcat which provides extremely flexibility to all of us for forwarding anything and then redirect to anything.
First of all, we have to install socat.
sudo apt-get install socat
Then the command for forwarding is as simple as follow.
socat -d -d -lmlocal2 \
TCP4-LISTEN:81,su=nobody,fork,reuseaddr \
TCP4:192.168.16.55:81
It means all TCP connection to port 81 on local host will be redirected to 192.168.16.55 on port 81. The process will be degraded to run as nobody and multiple connections will be served by forking. It works! In addition to make it run smoothly as a system service, I adapted initscript from squid as follow.
#! /bin/sh # # socat Startup script for the socat # # NAME=socat DESC=socat DAEMON=/usr/bin/socat LIB=/usr/lib/socat SOCAT_ARGS="-d -d -lmlocal2" [ ! -f /etc/default/socat ] || . /etc/default/socat . /lib/lsb/init-functions PATH=/bin:/usr/bin:/sbin:/usr/sbin [ -x $DAEMON ] || exit 0 # # Try to increase the # of filedescriptors we can open. # maxfds () { [ -n "$SOCAT_MAXFD" ] || return [ -f /proc/sys/fs/file-max ] || return 0 [ $SOCAT_MAXFD -le 4096 ] || SQUID_MAXFD=4096 global_file_max=`cat /proc/sys/fs/file-max` minimal_file_max=$(($SOCAT_MAXFD + 4096)) if [ "$global_file_max" -lt $minimal_file_max ] then echo $minimal_file_max > /proc/sys/fs/file-max fi ulimit -n $SOCAT_MAXFD } start_socat() { start-stop-daemon --quiet --start \ --pidfile /var/run/socat.$NAME.pid \ --background --make-pidfile \ --exec $DAEMON -- $SOCAT_ARGS $ARGS < /dev/null } stop_socat() { start-stop-daemon --stop --quiet --pidfile /var/run/socat.$NAME.pid --exec $DAEMON rm -f /var/run/socat.$NAME.pid } start () { echo "Starting $DESC:" maxfds umask 027 cd /tmp if test "x$AUTOSTART" = "xnone" -o -z "x$AUTOSTART" ; then echo "Autostart disabled." exit 0 fi for NAME in $AUTOSTART ; do ARGS=`eval echo \\\$SOCAT_$NAME` echo $ARGS start_socat echo " $NAME $ARGS" done return $? } stop () { echo -n "Stopping $DESC:" for PIDFILE in `ls /var/run/socat.*.pid 2> /dev/null`; do NAME=`echo $PIDFILE | cut -c16-` NAME=${NAME%%.pid} stop_socat echo -n " $NAME" done } case "$1" in start) log_daemon_msg "Starting socat" "socat" if start ; then log_end_msg $? else log_end_msg $? fi ;; stop) log_daemon_msg "Stopping socat" "socat" if stop ; then log_end_msg $? else log_end_msg $? fi ;; reload|force-reload|restart) log_daemon_msg "Restarting socat" "socat" stop if start ; then log_end_msg $? else log_end_msg $? fi ;; *) echo "Usage: /etc/init.d/$NAME {start|stop|reload|force-reload|restart}" exit 3 ;; esac exit 0
I saved this file in /etc/init.d/socat
and then registered to system service.
update-rc.d socat defaults
Lastly, configuration file must be created at /etc/default/socat
as follow.
AUTOSTART=default SOCAT_default="TCP4-LISTEN:81,su=nobody,fork,reuseaddr TCP4:192.168.16.55:81"
Now I can start/stop socat through initscript.
sudo /etc/init.d/socat start
sudo /etc/init.d/socat stop
For more examples, check them out at socat.
Tags: port forward, cisco vpn, socat, netcat
- sugree's blog
- 4924 reads
Post new comment