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