[tproxy] [stunnel patch] updated transparent proxy on linux 2.6 using cttproxy patch

MAtteo HCE Valsasna MAtteo.Valsasna at uninsubria.it
Fri Aug 26 16:53:52 CEST 2005


hello folks,

here comes an improved version of the transparent proxy patch, basically
solving the previous TODO issues.

please try it if you are interested in transparent stunnel. 

any feedback il welcome.

the code is heavly based on the examples distributed along with the
cttproxy patch, many thanks to Balzs Scheidler for its great work and to
Lennert Buytenhek for the skaidrus example program.

this code is (re)distributed under the GPL version 2

MAtteo


---README---
      cttproxy patch to stunnel

MAtteo HCE Valsasna (matteo dot valsasna at uninsubria dot it)
based on example code in cttproxy patch


ports stunnel transparent proxy to cttproxy kernel patch


allow stunnel server to connect to the application server faking the
stunnel client's IP source address. the server sees connections coming
from the stunnel client's IP address instead of that of the stunnel
server, and thus can apply admission control, bandwidth control,
logging policies as if the client connected directly.


should work 2.4 and 2.6 kernels and 2.0.x cttproxy patch

tested with kernel 2.6.12.5 and cttproxy-2.6.12-2.0.2 patch


setup:

* application server(s):
here run the application(s) you want to access trough stunnel

must route all traffic, or at least all traffic for
transproxyed connections, trough the stunnel server

* stunnel server:
must not be the same host as the application server

grab recent kernel source
patch your kernel source with the appropriate cttproxy patch
(from http://www.balabit.com/products/oss/tproxy/)

configure kernel with:
CONFIG_IP_NF_TPROXY=m
CONFIG_IP_NF_MATCH_TPROXY=m
CONFIG_IP_NF_TARGET_TPROXY=m


make and install kernel
reboot and choose patched kernel

load tproxy kernel modules
# modprobe iptable_tproxy
# modprobe ipt_tproxy

enable ip forwarding (this must act as a router)
# echo 1 > /proc/sys/net/ipv4/ip_forward

grab stunnel source and extract it
$ tar xzf stunnel-4.11.tar.gz

patch it
$ patch -p0 < cttproxy.patch

configure selecting tproxy support
$ ./configure --enable-tproxy

make and install
$ make 
# make install

run stunnel in server mode with 
transparent = yes 
remote = <application server>:<port>
in conf file

* stunnel client
run plain stunnel, 
client = yes
remote = stunnel server

* application client
may or may not be the same host as the stunnel client

connect to stunnel client to talk securely to application
server

---PATCH---diff -crb /tmp/stunnel-4.11/configure stunnel-4.11/configure
*** /tmp/stunnel-4.11/configure	2005-07-09 23:00:44.000000000 +0200
--- stunnel-4.11/configure	2005-08-25 16:59:57.000000000 +0200
***************
*** 463,469 ****
  # include <unistd.h>
  #endif"
  
! ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL ssldir RANDOM_FILE USE_DH USE_IPv6 LIBOBJS LTLIBOBJS'
  ac_subst_files=''
  
  # Initialize some variables set by options.
--- 463,469 ----
  # include <unistd.h>
  #endif"
  
! ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP LN_S RANLIB ac_ct_RANLIB EGREP ECHO AR ac_ct_AR CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL ssldir RANDOM_FILE USE_DH USE_IPv6 USE_TPROXY LIBOBJS LTLIBOBJS'
  ac_subst_files=''
  
  # Initialize some variables set by options.
***************
*** 1037,1042 ****
--- 1037,1043 ----
    --disable-rsa           Disable RSA support
    --enable-dh             Enable DH support
    --enable-ipv6           Enable IPv6 support
+   --enable-tproxy	  Enable linux 2.6 tproxy patch support
    --disable-libwrap       Disable TCP wrappers library support
  
  Optional Packages:
***************
*** 23166,23171 ****
--- 23344,23367 ----
  fi;
  
  
+ # use linux 2.[46] tproxy patch
+ echo "$as_me:$LINENO: checking whether to enable transparent proxyng using linux 2.46 tproxy patch" >&5
+ echo $ECHO_N "checking whether to enable transparent proxyng using linux 2.46 tproxy patch... $ECHO_C" >&6
+ # Check whether --enable-tproxy or --disable-tproxy was given.
+ if test "${enable_tproxy+set}" = set; then
+   enableval="$enable_tproxy"
+   echo "$as_me:$LINENO: result: yes" >&5
+ echo "${ECHO_T}yes" >&6; cat >>confdefs.h <<\_ACEOF
+ #define USE_TPROXY 1
+ _ACEOF
+ 
+ else
+   echo "$as_me:$LINENO: result: no" >&5
+ echo "${ECHO_T}no" >&6
+ 
+ fi;
+ 
+ 
  # Disable use of libwrap (TCP wrappers)
  # it should be the last check!
  echo "$as_me:$LINENO: checking whether to disable TCP wrappers library support" >&5
***************
*** 23987,23992 ****
--- 24184,24190 ----
  s, at RANDOM_FILE@,$RANDOM_FILE,;t t
  s, at USE_DH@,$USE_DH,;t t
  s, at USE_IPv6@,$USE_IPv6,;t t
+ s, at USE_TPROXY@,$USE_TPROXY,;t t
  s, at LIBOBJS@,$LIBOBJS,;t t
  s, at LTLIBOBJS@,$LTLIBOBJS,;t t
  CEOF
diff -crb /tmp/stunnel-4.11/configure.ac stunnel-4.11/configure.ac
*** /tmp/stunnel-4.11/configure.ac	2005-07-09 22:58:05.000000000 +0200
--- stunnel-4.11/configure.ac	2005-08-25 16:56:33.000000000 +0200
***************
*** 14,21 ****
--- 14,24 ----
  if test "$GCC" = "yes"
  then CFLAGS="$CFLAGS -Wall -Wshadow -Wcast-align -Wpointer-arith"
  fi
+ AC_PROG_CPP
  AC_PROG_INSTALL
+ AC_PROG_LN_S
  AC_PROG_MAKE_SET
+ AC_PROG_RANLIB
  
  # Checks for typedefs, structures, and compiler characteristics
  # AC_C_CONST
***************
*** 254,259 ****
--- 257,271 ----
  )
  AC_SUBST(USE_IPv6)
  
+ # use linux 2.[46] tproxy patch
+ AC_MSG_CHECKING([whether to enable transparent proxyng using linux 2.[46] tproxy patch])
+ AC_ARG_ENABLE(tproxy,
+ [  --enable-tproxy	  Enable linux 2.6 tproxy patch support],
+     [AC_MSG_RESULT([yes]); AC_DEFINE(USE_TPROXY)],
+     [AC_MSG_RESULT([no])]
+ )
+ AC_SUBST(USE_TPROXY)
+ 
  # Disable use of libwrap (TCP wrappers)
  # it should be the last check!
  AC_MSG_CHECKING([whether to disable TCP wrappers library support])
diff -crb /tmp/stunnel-4.11/src/client.c stunnel-4.11/src/client.c
*** /tmp/stunnel-4.11/src/client.c	2005-07-02 08:55:58.000000000 +0200
--- stunnel-4.11/src/client.c	2005-08-26 16:01:34.000000000 +0200
***************
*** 44,49 ****
--- 44,65 ----
  #define SHUT_RDWR 2
  #endif
  
+ #ifdef USE_TPROXY
+ #define LINUX_NETFILTER
+ #define LINUX_TPROXY
+ #define TPROXY_MAJOR_VERSION(x) ((x >> 24) & 0xff)
+ #define TPROXY_MINOR_VERSION(x) ((x >> 16) & 0xff)
+ #define TPROXY_PATCH_VERSION(x) (x & 0xffff)
+ #endif
+ 
+ /* transparent proxy */
+ #ifdef LINUX_NETFILTER
+ #include <linux/netfilter_ipv4.h>
+ #endif
+ #ifdef LINUX_TPROXY
+ #include <linux/netfilter_ipv4/ip_tproxy.h>
+ #endif
+ 
  /* TCP wrapper */
  #ifdef USE_LIBWRAP
  #include <tcpd.h>
***************
*** 77,82 ****
--- 93,103 ----
  static int connect_wait(CLI *, int, int);
  static void reset(int, char *);
  
+ #ifdef USE_TPROXY
+ static int determine_source_address(struct sockaddr_in *destination,
+ 				    struct sockaddr_in *source);
+ #endif
+ 
  int max_clients;
  #ifndef USE_WIN32
  int max_fds;
***************
*** 921,926 ****
--- 942,954 ----
      int s; /* destination socket */
      u16 i;
  
+     //    struct in_addr *local=NULL;
+ #ifdef USE_TPROXY
+     int f;
+     struct in_tproxy itp;
+     struct sockaddr_in tproxy_sin;
+ #endif
+ 
      /* setup address_list */
      if(c->opt->option.delayed_lookup) {
          resolved_list.num=0;
***************
*** 945,959 ****
          if(alloc_fd(s))
              return -1;
  
!         if(c->bind_addr.num) { /* explicit local bind or transparent proxy */
              memcpy(&bind_addr, &c->bind_addr.addr[0], sizeof(SOCKADDR_UNION));
              if(bind(s, &bind_addr.sa, addr_len(bind_addr))<0) {
                  sockerror("bind transparent");
                  closesocket(s);
                  return -1;
              }
          }
  
          /* try to connect for the 1st time */
          s_ntop(c->connecting_address, &addr);
          s_log(LOG_DEBUG, "%s connecting %s",
--- 973,1066 ----
          if(alloc_fd(s))
              return -1;
  
!         if(c->bind_addr.num
! #ifdef USE_TPROXY
! 	   /* if we're using the tproxy patch, transparent proxy is
! 	      handled below */
! 	   && !c->opt->option.transparent
! #endif
! 	   ) { 
! 	  /* explicit local bind, not tproxy transparent mode */
! 	  
  	  memcpy(&bind_addr, &c->bind_addr.addr[0], sizeof(SOCKADDR_UNION));
  	  if(bind(s, &bind_addr.sa, addr_len(bind_addr))<0) {
  	    sockerror("bind transparent");
  	    closesocket(s);
  	    return -1;
  	  }
+ 	  sockerror("local bind succeeded");
  	}
  
+ #ifdef USE_TPROXY
+ 	if (c->opt->option.transparent){
+ 	  /* transparent proxy support on 2.[46] linux kernels */
+ 	  /* added by MAtteo HCE Valsasna (matteo.valsasna at uninsubria.it), 20050826 */
+ 	  /* requires tproxy kernel patch (http://www.balabit.com/products/oss/tproxy */
+ 	  /* based on examples in cttproxy patch */
+ 	  /* this patch is released under the GNU General Public Licence, Version 2 */
+ 
+ 	  memcpy(&bind_addr, &c->bind_addr.addr[0], sizeof(SOCKADDR_UNION));
+ 
+ 	  /* check tproxy version */
+ 	  itp.op = TPROXY_VERSION;
+ 	  itp.v.version = 0x00000000;
+ 
+ 	  getsockopt(s, SOL_IP, IP_TPROXY, &itp, &f);
+ 	  s_log(LOG_NOTICE, "TPROXY_VERSION: %d.%d.%d", 
+ 		TPROXY_MAJOR_VERSION(itp.v.version),
+ 		TPROXY_MINOR_VERSION(itp.v.version),
+ 		TPROXY_PATCH_VERSION(itp.v.version));
+ 
+ 	  /* conservative: accepting only  tproxy version 2.0.x */
+ 	  if (TPROXY_MAJOR_VERSION(itp.v.version) != 2 || 
+ 	      TPROXY_MINOR_VERSION(itp.v.version) != 0) 
+ 	    {
+ 	    s_log(LOG_ERR, "unsupported tproxy version: %x (2.0.x required)", itp.v.version);
+ 	    return -1;
+ 	  }
+ 	  
+ 	  tproxy_sin.sin_family = AF_INET;
+ 	  if (determine_source_address(&addr.in, &tproxy_sin) < 0){
+ 	    sockerror("determine_source_address");
+ 	    return -1;
+ 	  }
+ 
+ 	  /* do not request a specific source port */
+ 	  tproxy_sin.sin_port = htons(0);
+ 	  
+ 	  /* bind to local source address */
+ 	  /* needed for tproxy magic */
+ 	  if (bind(s, (struct sockaddr *) &tproxy_sin, sizeof(tproxy_sin)) == -1)
+ 	    {
+ 	      sockerror("bind");
+ 	      return -1;
+ 	    }
+ 	  s_log(LOG_NOTICE, "bound to local: %s", inet_ntoa(tproxy_sin.sin_addr));
+ 
+ 	  /* assign foreign address */
+ 	  itp.op = TPROXY_ASSIGN;
+ 	  itp.v.addr.faddr = bind_addr.in.sin_addr;
+ 	  itp.v.addr.fport = 0;
+ 
+ 	  if (setsockopt(s, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1)
+ 	    {
+ 	      s_log(LOG_NOTICE, "error assigning foreign address: %s", inet_ntoa(bind_addr.in.sin_addr));
+ 	      sockerror("setsockopt(SOL_IP, IP_TPROXY, TPROXY_ASSIGN)");
+ 	      return -1;
+ 	    }
+   	  s_log(LOG_NOTICE, "assigned foreign address: %s", inet_ntoa(bind_addr.in.sin_addr));
+ 
+ 	  /* set connect flag on socket */
+ 	  itp.op = TPROXY_FLAGS;
+ 	  itp.v.flags = ITP_CONNECT|ITP_ONCE;
+ 	  if (setsockopt(s, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1)
+ 	    {
+ 	      sockerror("setsockopt(SOL_IP, IP_TPROXY, TPROXY_FLAGS)");
+ 	      return -1;
+ 	    }
+ 	}
+ #endif	  
+ 	
  	/* try to connect for the 1st time */
          s_ntop(c->connecting_address, &addr);
          s_log(LOG_DEBUG, "%s connecting %s",
***************
*** 1020,1023 ****
--- 1127,1175 ----
          log_error(LOG_DEBUG, get_last_socket_error(), txt);
  }
  
+ 
+ #ifdef USE_TPROXY
+ 
+ /* from skaidrus */
+ static int determine_source_address(struct sockaddr_in *destination,
+ 				    struct sockaddr_in *source)
+ {
+ 	struct sockaddr_in addr;
+ 	socklen_t addrlen;
+ 	char textaddr[32];
+ 	int sock;
+ 
+ 	sock = socket(AF_INET, SOCK_DGRAM, 0);
+ 	if (sock < 0) {
+ 		syslog(LOG_CRIT, "determine_source_address: error "
+ 				 "%d while creating socket", errno);
+ 		abort();
+ 	}
+ 
+ 	addr = *destination;
+ 	addr.sin_port = htons(80);
+ 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ 		syslog(LOG_ALERT, "determine_source_address: error %d "
+ 				  "while looking up route for %d", errno,
+ 				  inet_aton(textaddr, &(addr.sin_addr)));
+ 		close(sock);
+ 		return -1;
+ 	}
+ 
+ 	addrlen = sizeof(*source);
+ 	if (getsockname(sock, (struct sockaddr *)source, &addrlen) < 0) {
+ 		syslog(LOG_CRIT, "determine_source_address: error %d "
+ 				 "while retrieving source address", errno);
+ 		abort();
+ 	}
+ 	source->sin_port = 0;
+ 
+ 	close(sock);
+ 
+ 	return 0;
+ }
+ 
+ #endif
+ 
+ 
  /* End of client.c */




More information about the tproxy mailing list