diff --git a/Changes b/Changes index 5820667b..36507476 100644 --- a/Changes +++ b/Changes @@ -1,47 +1,74 @@ -Changelog ---------- +shadowsocks (1.4.3-1) unstable; urgency=low -1.4.2 -- Sun, 05 Jan 2014 10:05:29 +0900 + * Add tunnel mode with local port forwarding feature. + + -- Max Lv Fri, 21 Feb 2014 11:52:13 +0900 + +shadowsocks (1.4.2-1) unstable; urgency=high * Fix the UDP relay issues. * Add syslog support. -1.4.1 -- Tue, 12 Nov 2013 03:57:21 +0000 + -- Max Lv Sun, 05 Jan 2014 10:05:29 +0900 + +shadowsocks (1.4.1-1) unstable; urgency=low * Add multi-port support. * Add PolarSSL support by @linusyang. -1.4.0 -- Sun, 08 Sep 2013 02:20:40 +0000 + -- Max Lv Tue, 12 Nov 2013 03:57:21 +0000 + +shadowsocks (1.4.0-1) unstable; urgency=low * Add standard socks5 udp support. -1.3.3 -- Fri, 21 Jun 2013 09:59:20 +0800 + -- Max Lv Sun, 08 Sep 2013 02:20:40 +0000 + +shadowsocks (1.3.3-1) unstable; urgency=high * Provide more info in verbose mode. -1.3.2 -- Sun, 09 Jun 2013 09:52:31 +0000 + -- Max Lv Fri, 21 Jun 2013 09:59:20 +0800 + +shadowsocks (1.3.2-1) unstable; urgency=high * Fix some ciphers by @linusyang. -1.3.1 -- Tue, 04 Jun 2013 00:56:17 +0000 + -- Max Lv Sun, 09 Jun 2013 09:52:31 +0000 + +shadowsocks (1.3.1-1) unstable; urgency=low * Support more cihpers: camellia, idea, rc2 and seed. -1.3 -- Thu, 16 May 2013 10:51:15 +0800 + -- Max Lv Tue, 04 Jun 2013 00:56:17 +0000 + +shadowsocks (1.3-1) unstable; urgency=low + + * Able to bind connections to specific interface. + * Support more ciphers: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb. + + -- Max Lv Thu, 16 May 2013 10:51:15 +0800 + +shadowsocks (1.2-2) unstable; urgency=low + + * Close timeouted TCP connections. + + -- Max Lv Tue, 07 May 2013 14:10:33 +0800 + +shadowsocks (1.2-1) unstable; urgency=low - * Able to bind connections to specific interface - * Support more ciphers: aes-128-cfb, aes-192-cfb, aes-256-cfb, bf-cfb, cast5-cfb, des-cfb + * Fix a high load issue. -1.2 -- Tue, 07 May 2013 14:10:33 +0800 + -- Max Lv Thu, 18 Apr 2013 10:52:34 +0800 - * Close timeouted TCP connections - * Fix a high load issue +shadowsocks (1.1-1) unstable; urgency=low -1.1 -- Wed, 10 Apr 2013 12:11:36 +0800 + * Fix a IPV6 resolve issue. - * Fix a IPV6 resolve issue + -- Max Lv Wed, 10 Apr 2013 12:11:36 +0800 -1.0 -- Sat, 06 Apr 2013 16:59:15 +0800 +shadowsocks (1.0-2) unstable; urgency=low - * Initial release + * Initial release. + -- Max Lv Sat, 06 Apr 2013 16:59:15 +0800 diff --git a/configure b/configure index db0ea182..3e4a8261 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for shadowsocks 1.4.2. +# Generated by GNU Autoconf 2.69 for shadowsocks 1.4.3. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='shadowsocks' PACKAGE_TARNAME='shadowsocks' -PACKAGE_VERSION='1.4.2' -PACKAGE_STRING='shadowsocks 1.4.2' +PACKAGE_VERSION='1.4.3' +PACKAGE_STRING='shadowsocks 1.4.3' PACKAGE_BUGREPORT='max.c.lv@gmail.com' PACKAGE_URL='' @@ -1324,7 +1324,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures shadowsocks 1.4.2 to adapt to many kinds of systems. +\`configure' configures shadowsocks 1.4.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1394,7 +1394,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of shadowsocks 1.4.2:";; + short | recursive ) echo "Configuration of shadowsocks 1.4.3:";; esac cat <<\_ACEOF @@ -1510,7 +1510,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -shadowsocks configure 1.4.2 +shadowsocks configure 1.4.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2033,7 +2033,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by shadowsocks $as_me 1.4.2, which was +It was created by shadowsocks $as_me 1.4.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2853,7 +2853,7 @@ fi # Define the identity of the package. PACKAGE='shadowsocks' - VERSION='1.4.2' + VERSION='1.4.3' cat >>confdefs.h <<_ACEOF @@ -15450,7 +15450,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by shadowsocks $as_me 1.4.2, which was +This file was extended by shadowsocks $as_me 1.4.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15516,7 +15516,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -shadowsocks config.status 1.4.2 +shadowsocks config.status 1.4.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 21b1c80d..3fd5c1af 100755 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl -*- Autoconf -*- dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.67]) -AC_INIT([shadowsocks], [1.4.2], [max.c.lv@gmail.com]) +AC_INIT([shadowsocks], [1.4.3], [max.c.lv@gmail.com]) AC_CONFIG_SRCDIR([src/encrypt.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/debian/changelog b/debian/changelog index 2cea0ec6..36507476 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +shadowsocks (1.4.3-1) unstable; urgency=low + + * Add tunnel mode with local port forwarding feature. + + -- Max Lv Fri, 21 Feb 2014 11:52:13 +0900 + shadowsocks (1.4.2-1) unstable; urgency=high * Fix the UDP relay issues. diff --git a/src/Makefile.am b/src/Makefile.am index 7e7f2743..a9fbb8ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ AM_LDFLAGS = -static SS_COMMON_LIBS = $(top_builddir)/libev/libev.la $(INET_NTOP_LIB) -bin_PROGRAMS = ss-local +bin_PROGRAMS = ss-local ss-tunnel if !BUILD_WINCOMPAT bin_PROGRAMS += ss-server @@ -15,26 +15,39 @@ endif ss_local_SOURCES = utils.c \ jconf.c \ json.c \ - encrypt.c \ - udprelay.c \ - cache.c \ - local.c + encrypt.c \ + udprelay.c \ + cache.c \ + local.c + +ss_tunnel_SOURCES = utils.c \ + jconf.c \ + json.c \ + encrypt.c \ + udprelay.c \ + cache.c \ + tunnel.c + ss_server_SOURCES = utils.c \ jconf.c \ json.c \ encrypt.c \ - udprelay.c \ - cache.c \ + udprelay.c \ + cache.c \ server.c + ss_local_LDADD = $(SS_COMMON_LIBS) +ss_tunnel_LDADD = $(SS_COMMON_LIBS) ss_server_LDADD = $(SS_COMMON_LIBS) ss_server_LDADD += $(top_builddir)/libasyncns/libasyncns.la ss_local_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL +ss_tunnel_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL ss_server_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_REMOTE if BUILD_WINCOMPAT ss_local_SOURCES += win32.c +ss_tunnel_SOURCES += win32.c endif if BUILD_REDIRECTOR diff --git a/src/Makefile.in b/src/Makefile.in index 476d7285..d0d68970 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -51,10 +51,12 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -bin_PROGRAMS = ss-local$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) +bin_PROGRAMS = ss-local$(EXEEXT) ss-tunnel$(EXEEXT) $(am__EXEEXT_1) \ + $(am__EXEEXT_2) @BUILD_WINCOMPAT_FALSE@am__append_1 = ss-server @BUILD_WINCOMPAT_TRUE@am__append_2 = win32.c -@BUILD_REDIRECTOR_TRUE@am__append_3 = ss-redir +@BUILD_WINCOMPAT_TRUE@am__append_3 = win32.c +@BUILD_REDIRECTOR_TRUE@am__append_4 = ss-redir subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -106,6 +108,19 @@ ss_server_DEPENDENCIES = $(am__DEPENDENCIES_2) \ ss_server_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_server_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am__ss_tunnel_SOURCES_DIST = utils.c jconf.c json.c encrypt.c \ + udprelay.c cache.c tunnel.c win32.c +@BUILD_WINCOMPAT_TRUE@am__objects_2 = ss_tunnel-win32.$(OBJEXT) +am_ss_tunnel_OBJECTS = ss_tunnel-utils.$(OBJEXT) \ + ss_tunnel-jconf.$(OBJEXT) ss_tunnel-json.$(OBJEXT) \ + ss_tunnel-encrypt.$(OBJEXT) ss_tunnel-udprelay.$(OBJEXT) \ + ss_tunnel-cache.$(OBJEXT) ss_tunnel-tunnel.$(OBJEXT) \ + $(am__objects_2) +ss_tunnel_OBJECTS = $(am_ss_tunnel_OBJECTS) +ss_tunnel_DEPENDENCIES = $(am__DEPENDENCIES_2) +ss_tunnel_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_tunnel_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -119,9 +134,11 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(ss_local_SOURCES) $(ss_redir_SOURCES) $(ss_server_SOURCES) +SOURCES = $(ss_local_SOURCES) $(ss_redir_SOURCES) $(ss_server_SOURCES) \ + $(ss_tunnel_SOURCES) DIST_SOURCES = $(am__ss_local_SOURCES_DIST) \ - $(am__ss_redir_SOURCES_DIST) $(ss_server_SOURCES) + $(am__ss_redir_SOURCES_DIST) $(ss_server_SOURCES) \ + $(am__ss_tunnel_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -255,18 +272,22 @@ AM_LDFLAGS = -static SS_COMMON_LIBS = $(top_builddir)/libev/libev.la $(INET_NTOP_LIB) ss_local_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c cache.c \ local.c $(am__append_2) +ss_tunnel_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c \ + cache.c tunnel.c $(am__append_3) ss_server_SOURCES = utils.c \ jconf.c \ json.c \ encrypt.c \ - udprelay.c \ - cache.c \ + udprelay.c \ + cache.c \ server.c ss_local_LDADD = $(SS_COMMON_LIBS) +ss_tunnel_LDADD = $(SS_COMMON_LIBS) ss_server_LDADD = $(SS_COMMON_LIBS) \ $(top_builddir)/libasyncns/libasyncns.la ss_local_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL +ss_tunnel_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_LOCAL -DUDPRELAY_TUNNEL ss_server_CFLAGS = $(AM_CFLAGS) -DUDPRELAY_REMOTE @BUILD_REDIRECTOR_TRUE@ss_redir_SOURCES = utils.c \ @BUILD_REDIRECTOR_TRUE@ jconf.c \ @@ -364,6 +385,9 @@ ss-redir$(EXEEXT): $(ss_redir_OBJECTS) $(ss_redir_DEPENDENCIES) $(EXTRA_ss_redir ss-server$(EXEEXT): $(ss_server_OBJECTS) $(ss_server_DEPENDENCIES) $(EXTRA_ss_server_DEPENDENCIES) @rm -f ss-server$(EXEEXT) $(ss_server_LINK) $(ss_server_OBJECTS) $(ss_server_LDADD) $(LIBS) +ss-tunnel$(EXEEXT): $(ss_tunnel_OBJECTS) $(ss_tunnel_DEPENDENCIES) $(EXTRA_ss_tunnel_DEPENDENCIES) + @rm -f ss-tunnel$(EXEEXT) + $(ss_tunnel_LINK) $(ss_tunnel_OBJECTS) $(ss_tunnel_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -390,6 +414,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-udprelay.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-encrypt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-jconf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-json.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-tunnel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-udprelay.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_tunnel-win32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ .c.o: @@ -623,6 +655,118 @@ ss_server-server.obj: server.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi` +ss_tunnel-utils.o: utils.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-utils.o -MD -MP -MF $(DEPDIR)/ss_tunnel-utils.Tpo -c -o ss_tunnel-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-utils.Tpo $(DEPDIR)/ss_tunnel-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='ss_tunnel-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c + +ss_tunnel-utils.obj: utils.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-utils.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-utils.Tpo -c -o ss_tunnel-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-utils.Tpo $(DEPDIR)/ss_tunnel-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='ss_tunnel-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` + +ss_tunnel-jconf.o: jconf.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-jconf.o -MD -MP -MF $(DEPDIR)/ss_tunnel-jconf.Tpo -c -o ss_tunnel-jconf.o `test -f 'jconf.c' || echo '$(srcdir)/'`jconf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-jconf.Tpo $(DEPDIR)/ss_tunnel-jconf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jconf.c' object='ss_tunnel-jconf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-jconf.o `test -f 'jconf.c' || echo '$(srcdir)/'`jconf.c + +ss_tunnel-jconf.obj: jconf.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-jconf.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-jconf.Tpo -c -o ss_tunnel-jconf.obj `if test -f 'jconf.c'; then $(CYGPATH_W) 'jconf.c'; else $(CYGPATH_W) '$(srcdir)/jconf.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-jconf.Tpo $(DEPDIR)/ss_tunnel-jconf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jconf.c' object='ss_tunnel-jconf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-jconf.obj `if test -f 'jconf.c'; then $(CYGPATH_W) 'jconf.c'; else $(CYGPATH_W) '$(srcdir)/jconf.c'; fi` + +ss_tunnel-json.o: json.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-json.o -MD -MP -MF $(DEPDIR)/ss_tunnel-json.Tpo -c -o ss_tunnel-json.o `test -f 'json.c' || echo '$(srcdir)/'`json.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-json.Tpo $(DEPDIR)/ss_tunnel-json.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='json.c' object='ss_tunnel-json.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-json.o `test -f 'json.c' || echo '$(srcdir)/'`json.c + +ss_tunnel-json.obj: json.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-json.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-json.Tpo -c -o ss_tunnel-json.obj `if test -f 'json.c'; then $(CYGPATH_W) 'json.c'; else $(CYGPATH_W) '$(srcdir)/json.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-json.Tpo $(DEPDIR)/ss_tunnel-json.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='json.c' object='ss_tunnel-json.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-json.obj `if test -f 'json.c'; then $(CYGPATH_W) 'json.c'; else $(CYGPATH_W) '$(srcdir)/json.c'; fi` + +ss_tunnel-encrypt.o: encrypt.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-encrypt.o -MD -MP -MF $(DEPDIR)/ss_tunnel-encrypt.Tpo -c -o ss_tunnel-encrypt.o `test -f 'encrypt.c' || echo '$(srcdir)/'`encrypt.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-encrypt.Tpo $(DEPDIR)/ss_tunnel-encrypt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encrypt.c' object='ss_tunnel-encrypt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-encrypt.o `test -f 'encrypt.c' || echo '$(srcdir)/'`encrypt.c + +ss_tunnel-encrypt.obj: encrypt.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-encrypt.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-encrypt.Tpo -c -o ss_tunnel-encrypt.obj `if test -f 'encrypt.c'; then $(CYGPATH_W) 'encrypt.c'; else $(CYGPATH_W) '$(srcdir)/encrypt.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-encrypt.Tpo $(DEPDIR)/ss_tunnel-encrypt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encrypt.c' object='ss_tunnel-encrypt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-encrypt.obj `if test -f 'encrypt.c'; then $(CYGPATH_W) 'encrypt.c'; else $(CYGPATH_W) '$(srcdir)/encrypt.c'; fi` + +ss_tunnel-udprelay.o: udprelay.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-udprelay.o -MD -MP -MF $(DEPDIR)/ss_tunnel-udprelay.Tpo -c -o ss_tunnel-udprelay.o `test -f 'udprelay.c' || echo '$(srcdir)/'`udprelay.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-udprelay.Tpo $(DEPDIR)/ss_tunnel-udprelay.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='udprelay.c' object='ss_tunnel-udprelay.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-udprelay.o `test -f 'udprelay.c' || echo '$(srcdir)/'`udprelay.c + +ss_tunnel-udprelay.obj: udprelay.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-udprelay.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-udprelay.Tpo -c -o ss_tunnel-udprelay.obj `if test -f 'udprelay.c'; then $(CYGPATH_W) 'udprelay.c'; else $(CYGPATH_W) '$(srcdir)/udprelay.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-udprelay.Tpo $(DEPDIR)/ss_tunnel-udprelay.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='udprelay.c' object='ss_tunnel-udprelay.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-udprelay.obj `if test -f 'udprelay.c'; then $(CYGPATH_W) 'udprelay.c'; else $(CYGPATH_W) '$(srcdir)/udprelay.c'; fi` + +ss_tunnel-cache.o: cache.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-cache.o -MD -MP -MF $(DEPDIR)/ss_tunnel-cache.Tpo -c -o ss_tunnel-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-cache.Tpo $(DEPDIR)/ss_tunnel-cache.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cache.c' object='ss_tunnel-cache.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c + +ss_tunnel-cache.obj: cache.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-cache.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-cache.Tpo -c -o ss_tunnel-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-cache.Tpo $(DEPDIR)/ss_tunnel-cache.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cache.c' object='ss_tunnel-cache.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` + +ss_tunnel-tunnel.o: tunnel.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-tunnel.o -MD -MP -MF $(DEPDIR)/ss_tunnel-tunnel.Tpo -c -o ss_tunnel-tunnel.o `test -f 'tunnel.c' || echo '$(srcdir)/'`tunnel.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-tunnel.Tpo $(DEPDIR)/ss_tunnel-tunnel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tunnel.c' object='ss_tunnel-tunnel.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-tunnel.o `test -f 'tunnel.c' || echo '$(srcdir)/'`tunnel.c + +ss_tunnel-tunnel.obj: tunnel.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-tunnel.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-tunnel.Tpo -c -o ss_tunnel-tunnel.obj `if test -f 'tunnel.c'; then $(CYGPATH_W) 'tunnel.c'; else $(CYGPATH_W) '$(srcdir)/tunnel.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-tunnel.Tpo $(DEPDIR)/ss_tunnel-tunnel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tunnel.c' object='ss_tunnel-tunnel.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-tunnel.obj `if test -f 'tunnel.c'; then $(CYGPATH_W) 'tunnel.c'; else $(CYGPATH_W) '$(srcdir)/tunnel.c'; fi` + +ss_tunnel-win32.o: win32.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-win32.o -MD -MP -MF $(DEPDIR)/ss_tunnel-win32.Tpo -c -o ss_tunnel-win32.o `test -f 'win32.c' || echo '$(srcdir)/'`win32.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-win32.Tpo $(DEPDIR)/ss_tunnel-win32.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='win32.c' object='ss_tunnel-win32.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-win32.o `test -f 'win32.c' || echo '$(srcdir)/'`win32.c + +ss_tunnel-win32.obj: win32.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -MT ss_tunnel-win32.obj -MD -MP -MF $(DEPDIR)/ss_tunnel-win32.Tpo -c -o ss_tunnel-win32.obj `if test -f 'win32.c'; then $(CYGPATH_W) 'win32.c'; else $(CYGPATH_W) '$(srcdir)/win32.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ss_tunnel-win32.Tpo $(DEPDIR)/ss_tunnel-win32.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='win32.c' object='ss_tunnel-win32.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_tunnel_CFLAGS) $(CFLAGS) -c -o ss_tunnel-win32.obj `if test -f 'win32.c'; then $(CYGPATH_W) 'win32.c'; else $(CYGPATH_W) '$(srcdir)/win32.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/src/include.h b/src/include.h index d9514ded..9c8ed5c7 100644 --- a/src/include.h +++ b/src/include.h @@ -4,6 +4,9 @@ int udprelay_init(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL const char *remote_host, const char *remote_port, +#ifdef UDPRELAY_TUNNEL + const addr_t tunnel_addr, +#endif #endif #ifdef UDPRELAY_REMOTE asyncns_t *asyncns, diff --git a/src/jconf.c b/src/jconf.c index 581fafa8..510a55c6 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -35,7 +35,16 @@ static char *to_string(const json_value *value) return 0; } -static void parse_addr(const char *str, remote_addr_t *addr) { +void free_addr(addr_t *addr) +{ + free(addr->host); + free(addr->port); + addr->host = NULL; + addr->port = NULL; +} + +void parse_addr(const char *str, addr_t *addr) +{ int ret = -1, n = 0; char *pch; pch = strchr(str, ':'); @@ -52,13 +61,13 @@ static void parse_addr(const char *str, remote_addr_t *addr) { } if (ret == -1) { - addr->host = str; + addr->host = strdup(str); addr->port = NULL; } else { addr->host = ss_strndup(str, ret); - addr->port = str + ret + 1; + addr->port = strdup(str + ret + 1); } } diff --git a/src/jconf.h b/src/jconf.h index b687bccc..2bfc8c78 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -8,14 +8,14 @@ typedef struct { - const char *host; - const char *port; -} remote_addr_t; + char *host; + char *port; +} addr_t; typedef struct { int remote_num; - remote_addr_t remote_addr[MAX_REMOTE_NUM]; + addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port; char *local_addr; char *local_port; @@ -25,5 +25,7 @@ typedef struct } jconf_t; jconf_t *read_jconf(const char* file); +void parse_addr(const char *str, addr_t *addr); +void free_addr(addr_t *addr); #endif // _JCONF_H diff --git a/src/local.c b/src/local.c index 2b4f2694..b08612da 100644 --- a/src/local.c +++ b/src/local.c @@ -766,7 +766,6 @@ static void accept_cb (EV_P_ ev_io *w, int revents) if (sockfd < 0) { ERROR("socket"); - close(sockfd); freeaddrinfo(res); return; } @@ -808,7 +807,7 @@ int main (int argc, char **argv) char *iface = NULL; int remote_num = 0; - remote_addr_t remote_addr[MAX_REMOTE_NUM]; + addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; @@ -929,7 +928,7 @@ int main (int argc, char **argv) // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; - listen_ctx.remote_addr = malloc(sizeof(remote_addr_t) * remote_num); + listen_ctx.remote_addr = malloc(sizeof(addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; diff --git a/src/local.h b/src/local.h index f67f2852..35596115 100644 --- a/src/local.h +++ b/src/local.h @@ -10,7 +10,7 @@ struct listen_ctx { ev_io io; - remote_addr_t *remote_addr; + addr_t *remote_addr; char *iface; int remote_num; int method; diff --git a/src/redir.c b/src/redir.c index 7379ef53..9167f9bd 100644 --- a/src/redir.c +++ b/src/redir.c @@ -630,7 +630,6 @@ static void accept_cb (EV_P_ ev_io *w, int revents) if (sockfd < 0) { ERROR("socket"); - close(sockfd); freeaddrinfo(res); return; } @@ -670,7 +669,7 @@ int main (int argc, char **argv) char *conf_path = NULL; int remote_num = 0; - remote_addr_t remote_addr[MAX_REMOTE_NUM]; + addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; @@ -778,7 +777,7 @@ int main (int argc, char **argv) // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; - listen_ctx.remote_addr = malloc(sizeof(remote_addr_t) * remote_num); + listen_ctx.remote_addr = malloc(sizeof(addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; diff --git a/src/redir.h b/src/redir.h index da765ee8..6e18e9c5 100644 --- a/src/redir.h +++ b/src/redir.h @@ -8,7 +8,7 @@ struct listen_ctx { ev_io io; - remote_addr_t *remote_addr; + addr_t *remote_addr; int remote_num; int timeout; int fd; diff --git a/src/tunnel.c b/src/tunnel.c new file mode 100644 index 00000000..dfbf835e --- /dev/null +++ b/src/tunnel.c @@ -0,0 +1,884 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __MINGW32__ +#include +#include +#include +#include +#include +#include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) +#include +#include +#define SET_INTERFACE +#endif + +#ifdef __MINGW32__ +#include "win32.h" +#endif + +#include "utils.h" +#include "tunnel.h" + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +#ifndef BUF_SIZE +#define BUF_SIZE 512 +#endif + +int verbose = 0; +int udprelay = 0; + +#ifndef __MINGW32__ +static int setnonblocking(int fd) +{ + int flags; + if (-1 ==(flags = fcntl(fd, F_GETFL, 0))) + flags = 0; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} +#endif + +#ifdef SET_INTERFACE +int setinterface(int socket_fd, const char* interface_name) +{ + struct ifreq interface; + memset(&interface, 0, sizeof(interface)); + strncpy(interface.ifr_name, interface_name, IFNAMSIZ); + int res = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(struct ifreq)); + return res; +} +#endif + +int create_and_bind(const char *addr, const char *port) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int s, listen_sock; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ + hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ + + s = getaddrinfo(addr, port, &hints, &result); + if (s != 0) + { + LOGD("getaddrinfo: %s", gai_strerror(s)); + return -1; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) + { + listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (listen_sock == -1) + continue; + + int opt = 1; + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + setsockopt(listen_sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + + s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); + if (s == 0) + { + /* We managed to bind successfully! */ + break; + } + else + { + ERROR("bind"); + } + + close(listen_sock); + } + + if (rp == NULL) + { + LOGE("Could not bind"); + return -1; + } + + freeaddrinfo(result); + + return listen_sock; +} + +static void server_recv_cb (EV_P_ ev_io *w, int revents) +{ + struct server_ctx *server_recv_ctx = (struct server_ctx *)w; + struct server *server = server_recv_ctx->server; + struct remote *remote = server->remote; + + if (remote == NULL) + { + close_and_free_server(EV_A_ server); + return; + } + + ssize_t r = recv(server->fd, remote->buf, BUF_SIZE, 0); + + if (r == 0) + { + // connection closed + remote->buf_len = 0; + remote->buf_idx = 0; + close_and_free_server(EV_A_ server); + if (remote != NULL) + { + ev_io_start(EV_A_ &remote->send_ctx->io); + } + return; + } + else if(r < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + // no data + // continue to wait for recv + return; + } + else + { + ERROR("server recv"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + + remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx); + + if (remote->buf == NULL) + { + LOGE("invalid password or cipher"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + + int s = send(remote->fd, remote->buf, r, 0); + + if(s == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + // no data, wait for send + remote->buf_len = r; + remote->buf_idx = 0; + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_io_start(EV_A_ &remote->send_ctx->io); + return; + } + else + { + ERROR("send"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + else if(s < r) + { + remote->buf_len = r - s; + remote->buf_idx = s; + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_io_start(EV_A_ &remote->send_ctx->io); + return; + } +} + +static void server_send_cb (EV_P_ ev_io *w, int revents) +{ + struct server_ctx *server_send_ctx = (struct server_ctx *)w; + struct server *server = server_send_ctx->server; + struct remote *remote = server->remote; + if (server->buf_len == 0) + { + // close and free + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + else + { + // has data to send + ssize_t s = send(server->fd, server->buf + server->buf_idx, + server->buf_len, 0); + if (s < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + { + ERROR("send"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + } + return; + } + else if (s < server->buf_len) + { + // partly sent, move memory, wait for the next time to send + server->buf_len -= s; + server->buf_idx += s; + return; + } + else + { + // all sent out, wait for reading + server->buf_len = 0; + server->buf_idx = 0; + ev_io_stop(EV_A_ &server_send_ctx->io); + if (remote != NULL) + { + ev_io_start(EV_A_ &remote->recv_ctx->io); + } + else + { + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + } + +} + +static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) +{ + struct remote_ctx *remote_ctx = (struct remote_ctx *) (((void*)watcher) + - sizeof(ev_io)); + struct remote *remote = remote_ctx->remote; + struct server *server = remote->server; + + LOGD("remote timeout"); + + ev_timer_stop(EV_A_ watcher); + + if (server == NULL) + { + close_and_free_remote(EV_A_ remote); + return; + } + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); +} + +static void remote_recv_cb (EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_recv_ctx->remote; + struct server *server = remote->server; + if (server == NULL) + { + close_and_free_remote(EV_A_ remote); + return; + } + + ssize_t r = recv(remote->fd, server->buf, BUF_SIZE, 0); + + if (r == 0) + { + // connection closed + server->buf_len = 0; + server->buf_idx = 0; + close_and_free_remote(EV_A_ remote); + if (server != NULL) + { + ev_io_start(EV_A_ &server->send_ctx->io); + } + return; + } + else if(r < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + // no data + // continue to wait for recv + return; + } + else + { + ERROR("remote recv"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + + server->buf = ss_decrypt(BUF_SIZE, server->buf, &r, server->d_ctx); + + if (server->buf == NULL) + { + LOGE("invalid password or cipher"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + + int s = send(server->fd, server->buf, r, 0); + + if (s == -1) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + // no data, wait for send + server->buf_len = r; + server->buf_idx = 0; + ev_io_stop(EV_A_ &remote_recv_ctx->io); + ev_io_start(EV_A_ &server->send_ctx->io); + return; + } + else + { + ERROR("send"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + else if (s < r) + { + server->buf_len = r - s; + server->buf_idx = s; + ev_io_stop(EV_A_ &remote_recv_ctx->io); + ev_io_start(EV_A_ &server->send_ctx->io); + return; + } +} + +static void remote_send_cb (EV_P_ ev_io *w, int revents) +{ + struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_send_ctx->remote; + struct server *server = remote->server; + + if (!remote_send_ctx->connected) + { + + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + int r = getpeername(remote->fd, (struct sockaddr*)&addr, &len); + if (r == 0) + { + remote_send_ctx->connected = 1; + ev_io_stop(EV_A_ &remote_send_ctx->io); + ev_timer_stop(EV_A_ &remote_send_ctx->watcher); + + // send destaddr + char *addr_to_send = malloc(BUF_SIZE); + ssize_t addr_len = 0; + struct sockaddr *sa = &server->destaddr; + addr_to_send[addr_len++] = 1; + + if (sa->sa_family == AF_INET) + { + // handle IPv4 + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + size_t in_addr_len = sizeof(struct in_addr); + memcpy(addr_to_send + addr_len, &sin->sin_addr, in_addr_len); + addr_len += in_addr_len; + memcpy(addr_to_send + addr_len, &sin->sin_port, 2); + addr_len += 2; + } + else if (sa->sa_family == AF_INET6) + { + // handle IPv6 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + size_t in6_addr_len = sizeof(struct in6_addr); + memcpy(addr_to_send + addr_len, &sin6->sin6_addr, in6_addr_len); + addr_len += in6_addr_len; + memcpy(addr_to_send + addr_len, &sin6->sin6_port, 2); + addr_len += 2; + } + else + { + LOGE("unsupported addr type"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + + addr_to_send = ss_encrypt(BUF_SIZE, addr_to_send, &addr_len, server->e_ctx); + if (addr_to_send == NULL) + { + LOGE("invalid password or cipher"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + + int s = send(remote->fd, addr_to_send, addr_len, 0); + free(addr_to_send); + + if (s < addr_len) + { + LOGE("failed to send remote addr."); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + } + + ev_io_start(EV_A_ &remote->recv_ctx->io); + ev_io_start(EV_A_ &server->recv_ctx->io); + + return; + } + else + { + ERROR("getpeername"); + // not connected + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + else + { + if (remote->buf_len == 0) + { + // close and free + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + else + { + // has data to send + ssize_t s = send(remote->fd, remote->buf + remote->buf_idx, + remote->buf_len, 0); + if (s < 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + { + ERROR("send"); + // close and free + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + } + return; + } + else if (s < remote->buf_len) + { + // partly sent, move memory, wait for the next time to send + remote->buf_len -= s; + remote->buf_idx += s; + return; + } + else + { + // all sent out, wait for reading + remote->buf_len = 0; + remote->buf_idx = 0; + ev_io_stop(EV_A_ &remote_send_ctx->io); + if (server != NULL) + { + ev_io_start(EV_A_ &server->recv_ctx->io); + } + else + { + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + } + + } +} + +struct remote* new_remote(int fd, int timeout) +{ + struct remote *remote; + remote = malloc(sizeof(struct remote)); + remote->buf = malloc(BUF_SIZE); + remote->recv_ctx = malloc(sizeof(struct remote_ctx)); + remote->send_ctx = malloc(sizeof(struct remote_ctx)); + remote->fd = fd; + ev_io_init(&remote->recv_ctx->io, remote_recv_cb, fd, EV_READ); + ev_io_init(&remote->send_ctx->io, remote_send_cb, fd, EV_WRITE); + ev_timer_init(&remote->send_ctx->watcher, remote_timeout_cb, timeout, 0); + remote->recv_ctx->remote = remote; + remote->recv_ctx->connected = 0; + remote->send_ctx->remote = remote; + remote->send_ctx->connected = 0; + remote->buf_len = 0; + remote->buf_idx = 0; + return remote; +} + +static void free_remote(struct remote *remote) +{ + if (remote != NULL) + { + if (remote->server != NULL) + { + remote->server->remote = NULL; + } + if (remote->buf) + { + free(remote->buf); + } + free(remote->recv_ctx); + free(remote->send_ctx); + free(remote); + } +} + +static void close_and_free_remote(EV_P_ struct remote *remote) +{ + if (remote != NULL) + { + ev_timer_stop(EV_A_ &remote->send_ctx->watcher); + ev_io_stop(EV_A_ &remote->send_ctx->io); + ev_io_stop(EV_A_ &remote->recv_ctx->io); + close(remote->fd); + free_remote(remote); + } +} + +struct server* new_server(int fd, int method) +{ + struct server *server; + server = malloc(sizeof(struct server)); + server->buf = malloc(BUF_SIZE); + server->recv_ctx = malloc(sizeof(struct server_ctx)); + server->send_ctx = malloc(sizeof(struct server_ctx)); + server->fd = fd; + ev_io_init(&server->recv_ctx->io, server_recv_cb, fd, EV_READ); + ev_io_init(&server->send_ctx->io, server_send_cb, fd, EV_WRITE); + server->recv_ctx->server = server; + server->recv_ctx->connected = 0; + server->send_ctx->server = server; + server->send_ctx->connected = 0; + if (method) + { + server->e_ctx = malloc(sizeof(struct enc_ctx)); + server->d_ctx = malloc(sizeof(struct enc_ctx)); + enc_ctx_init(method, server->e_ctx, 1); + enc_ctx_init(method, server->d_ctx, 0); + } + else + { + server->e_ctx = NULL; + server->d_ctx = NULL; + } + server->buf_len = 0; + server->buf_idx = 0; + return server; +} + +static void free_server(struct server *server) +{ + if (server != NULL) + { + if (server->remote != NULL) + { + server->remote->server = NULL; + } + if (server->e_ctx != NULL) + { + cipher_context_release(&server->e_ctx->evp); + free(server->e_ctx); + } + if (server->d_ctx != NULL) + { + cipher_context_release(&server->d_ctx->evp); + free(server->d_ctx); + } + if (server->buf) + { + free(server->buf); + } + free(server->recv_ctx); + free(server->send_ctx); + free(server); + } +} + +static void close_and_free_server(EV_P_ struct server *server) +{ + if (server != NULL) + { + ev_io_stop(EV_A_ &server->send_ctx->io); + ev_io_stop(EV_A_ &server->recv_ctx->io); + close(server->fd); + free_server(server); + } +} + +static void accept_cb (EV_P_ ev_io *w, int revents) +{ + struct listen_ctx *listener = (struct listen_ctx *)w; + int serverfd = accept(listener->fd, NULL, NULL); + if (serverfd == -1) + { + ERROR("accept"); + return; + } + setnonblocking(serverfd); + int opt = 1; + setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + + struct addrinfo hints, *res, *dest; + int sockfd; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + int index = rand() % listener->remote_num; + if (verbose) + { + LOGD("connect to %s:%s", listener->remote_addr[index].host, listener->remote_addr[index].port); + } + int err = getaddrinfo(listener->remote_addr[index].host, listener->remote_addr[index].port, &hints, &res); + if (err) + { + ERROR("getaddrinfo"); + return; + } + + err = getaddrinfo(listener->tunnel_addr.host, listener->tunnel_addr.port, &hints, &dest); + if (err) + { + freeaddrinfo(res); + ERROR("getaddrinfo"); + return; + } + + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sockfd < 0) + { + ERROR("socket"); + freeaddrinfo(res); + freeaddrinfo(dest); + return; + } + + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + + // Setup + setnonblocking(sockfd); +#ifdef SET_INTERFACE + if (listener->iface) setinterface(sockfd, listener->iface); +#endif + + struct server *server = new_server(serverfd, listener->method); + struct remote *remote = new_remote(sockfd, listener->timeout); + server->destaddr = *dest->ai_addr; + server->remote = remote; + remote->server = server; + connect(sockfd, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + freeaddrinfo(dest); + // listen to remote connected event + ev_io_start(EV_A_ &remote->send_ctx->io); + ev_timer_start(EV_A_ &remote->send_ctx->watcher); +} + +int main (int argc, char **argv) +{ + + int i, c; + int pid_flags = 0; + char *local_port = NULL; + char *local_addr = NULL; + char *password = NULL; + char *timeout = NULL; + char *method = NULL; + char *pid_path = NULL; + char *conf_path = NULL; + char *iface = NULL; + + int remote_num = 0; + addr_t remote_addr[MAX_REMOTE_NUM]; + char *remote_port = NULL; + + addr_t tunnel_addr = {.host = NULL, .port = NULL}; + char *tunnel_addr_str = NULL; + + opterr = 0; + + while ((c = getopt (argc, argv, "f:s:p:l:k:t:m:i:c:b:L:uv")) != -1) + { + switch (c) + { + case 's': + remote_addr[remote_num].host = optarg; + remote_addr[remote_num++].port = NULL; + break; + case 'p': + remote_port = optarg; + break; + case 'l': + local_port = optarg; + break; + case 'k': + password = optarg; + break; + case 'f': + pid_flags = 1; + pid_path = optarg; + break; + case 't': + timeout = optarg; + break; + case 'm': + method = optarg; + break; + case 'c': + conf_path = optarg; + break; + case 'i': + iface = optarg; + break; + case 'b': + local_addr = optarg; + break; + case 'u': + udprelay = 1; + break; + case 'L': + tunnel_addr_str = optarg; + break; + case 'v': + verbose = 1; + break; + } + } + + if (opterr) + { + usage(); + exit(EXIT_FAILURE); + } + + if (conf_path != NULL) + { + jconf_t *conf = read_jconf(conf_path); + if (remote_num == 0) + { + remote_num = conf->remote_num; + for (i = 0; i < remote_num; i++) + { + remote_addr[i] = conf->remote_addr[i]; + } + } + if (remote_port == NULL) remote_port = conf->remote_port; + if (local_addr == NULL) local_addr = conf->local_addr; + if (local_port == NULL) local_port = conf->local_port; + if (password == NULL) password = conf->password; + if (method == NULL) method = conf->method; + if (timeout == NULL) timeout = conf->timeout; + } + + if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL || + local_port == NULL || password == NULL) + { + usage(); + exit(EXIT_FAILURE); + } + + if (timeout == NULL) timeout = "10"; + + if (local_addr == NULL) local_addr = "0.0.0.0"; + + if (pid_flags) + { + USE_SYSLOG(argv[0]); + demonize(pid_path); + } + + // parse tunnel addr + parse_addr(tunnel_addr_str, &tunnel_addr); + +#ifdef __MINGW32__ + winsock_init(); +#else + // ignore SIGPIPE + signal(SIGPIPE, SIG_IGN); + signal(SIGABRT, SIG_IGN); +#endif + + // Setup keys + LOGD("initialize ciphers... %s", method); + int m = enc_init(password, method); + + // Setup socket + int listenfd; + listenfd = create_and_bind(local_addr, local_port); + if (listenfd < 0) + { + FATAL("bind() error.."); + } + if (listen(listenfd, SOMAXCONN) == -1) + { + FATAL("listen() error."); + } + setnonblocking(listenfd); + LOGD("server listening at port %s.", local_port); + + // Setup proxy context + struct listen_ctx listen_ctx; + listen_ctx.tunnel_addr = tunnel_addr; + listen_ctx.remote_num = remote_num; + listen_ctx.remote_addr = malloc(sizeof(addr_t) * remote_num); + while (remote_num > 0) + { + int index = --remote_num; + if (remote_addr[index].port == NULL) remote_addr[index].port = remote_port; + listen_ctx.remote_addr[index] = remote_addr[index]; + } + listen_ctx.timeout = atoi(timeout); + listen_ctx.fd = listenfd; + listen_ctx.iface = iface; + listen_ctx.method = m; + + struct ev_loop *loop = ev_default_loop(0); + if (!loop) + { + FATAL("ev_loop error."); + } + ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); + ev_io_start (loop, &listen_ctx.io); + + // Setup UDP + if (udprelay) + { + LOGD("udprelay enabled."); + udprelay_init(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, + tunnel_addr, m, listen_ctx.timeout, iface); + } + + ev_run (loop, 0); + +#ifdef __MINGW32__ + winsock_cleanup(); +#endif + + return 0; +} + diff --git a/src/tunnel.h b/src/tunnel.h new file mode 100644 index 00000000..bd0f6d48 --- /dev/null +++ b/src/tunnel.h @@ -0,0 +1,76 @@ +#ifndef _LOCAL_H +#define _LOCAL_H + +#include +#include "encrypt.h" +#include "jconf.h" + +#include "include.h" + +struct listen_ctx +{ + ev_io io; + addr_t tunnel_addr; + addr_t *remote_addr; + char *iface; + int remote_num; + int method; + int timeout; + int fd; + struct sockaddr sock; +}; + +struct server_ctx +{ + ev_io io; + int connected; + struct server *server; +}; + +struct server +{ + int fd; + int buf_len; + int buf_idx; + char *buf; // server send from, remote recv into + struct enc_ctx *e_ctx; + struct enc_ctx *d_ctx; + struct server_ctx *recv_ctx; + struct server_ctx *send_ctx; + struct remote *remote; + struct sockaddr destaddr; +}; + +struct remote_ctx +{ + ev_io io; + ev_timer watcher; + int connected; + struct remote *remote; +}; + +struct remote +{ + int fd; + int buf_len; + int buf_idx; + char *buf; // remote send from, server recv into + struct remote_ctx *recv_ctx; + struct remote_ctx *send_ctx; + struct server *server; +}; + +static void accept_cb (EV_P_ ev_io *w, int revents); +static void server_recv_cb (EV_P_ ev_io *w, int revents); +static void server_send_cb (EV_P_ ev_io *w, int revents); +static void remote_recv_cb (EV_P_ ev_io *w, int revents); +static void remote_send_cb (EV_P_ ev_io *w, int revents); +static void free_remote(struct remote *remote); +static void close_and_free_remote(EV_P_ struct remote *remote); +static void free_server(struct server *server); +static void close_and_free_server(EV_P_ struct server *server); + +struct remote* new_remote(int fd, int timeout); +struct server* new_server(int fd, int method); + +#endif // _TUNNEL_H diff --git a/src/udprelay.c b/src/udprelay.c index e97205cc..40a536db 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -473,6 +473,11 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) goto CLEAN_UP; } +#ifdef UDPRELAY_TUNNEL + // Construct packet + buf_len -= addr_header_len; + memmove(buf, buf + addr_header_len, buf_len); +#else // Construct packet char *tmpbuf = malloc(buf_len + 3); memset(tmpbuf, 0, 3); @@ -481,6 +486,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) buf = tmpbuf; buf_len += 3; #endif +#endif #ifdef UDPRELAY_REMOTE // Construct packet @@ -538,8 +544,10 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) #endif #ifdef UDPRELAY_LOCAL +#ifndef UDPRELAY_TUNNEL uint8_t frag = *(uint8_t*)(buf + 2); offset += 3; +#endif #endif /* @@ -581,6 +589,29 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) * */ +#ifdef UDPRELAY_TUNNEL + char addr_header[256] = {0}; + char* host = server_ctx->tunnel_addr.host; + char* port = server_ctx->tunnel_addr.port; + int host_len = strlen(host); + uint16_t port_num = (uint16_t)atoi(port); + uint16_t port_net_num = htons(port_num); + int addr_header_len = 2 + host_len + 2; + + // initialize the addr header + addr_header[0] = 3; + addr_header[1] = host_len; + memcpy(addr_header + 2, host, host_len); + memcpy(addr_header + 2 + host_len, &port_net_num, 2); + + // reconstruct the buffer + char *tmp = malloc(buf_len + addr_header_len); + memcpy(tmp, addr_header, addr_header_len); + memcpy(tmp + addr_header_len, buf, buf_len); + free(buf); + buf = tmp; + +#else char host[256] = {0}; char port[64] = {0}; @@ -592,6 +623,8 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) goto CLEAN_UP; } char *addr_header = buf + offset; +#endif + char *key = hash_key(addr_header, addr_header_len, &src_addr); struct cache *conn_cache = server_ctx->conn_cache; @@ -615,11 +648,13 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) #ifdef UDPRELAY_LOCAL +#ifndef UDPRELAY_TUNNEL if (frag) { LOGE("drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } +#endif if (remote_ctx == NULL) { @@ -675,8 +710,11 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) freeaddrinfo(result); } - buf_len -= offset; - memmove(buf, buf + offset, buf_len); + if (offset > 0) + { + buf_len -= offset; + memmove(buf, buf + offset, buf_len); + } buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); @@ -750,6 +788,9 @@ void free_cb(void *element) int udprelay_init(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL const char *remote_host, const char *remote_port, +#ifdef UDPRELAY_TUNNEL + const addr_t tunnel_addr, +#endif #endif #ifdef UDPRELAY_REMOTE asyncns_t *asyncns, @@ -783,6 +824,9 @@ int udprelay_init(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL server_ctx->remote_host = remote_host; server_ctx->remote_port = remote_port; +#ifdef UDPRELAY_TUNNEL + server_ctx->tunnel_addr = tunnel_addr; +#endif #endif #ifdef UDPRELAY_REMOTE server_ctx->asyncns = asyncns; diff --git a/src/udprelay.h b/src/udprelay.h index c20e6bb5..8a42b3dd 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -32,6 +32,9 @@ struct server_ctx #ifdef UDPRELAY_LOCAL const char *remote_host; const char *remote_port; +#ifdef UDPRELAY_TUNNEL + addr_t tunnel_addr; +#endif #endif }; diff --git a/src/utils.c b/src/utils.c index 7a18c90c..98612c87 100644 --- a/src/utils.c +++ b/src/utils.c @@ -82,9 +82,10 @@ void usage() { printf("\n"); printf("shadowsocks-libev %s\n\n", VERSION); - printf(" maintained by Max Lv \n\n"); + printf(" maintained by Max Lv \n"); + printf(" and Linus Yang \n\n"); printf(" usage:\n\n"); - printf(" ss-[local|redir|server]\n"); + printf(" ss-[local|redir|server|tunnel]\n"); printf(" -s host name or ip address of your remote server\n"); printf(" -p port number of your remote server\n"); printf(" -l port number of your local server\n"); @@ -100,11 +101,13 @@ void usage() printf(" [-c ] json format config file\n"); printf("\n"); printf(" [-i ] specific network interface to bind,\n"); - printf(" only available in local and server modes\n"); + printf(" not available in redir mode\n"); printf(" [-b ] specific local address to bind,\n"); - printf(" only available in local and redir modes\n"); + printf(" not available in server mode\n"); printf(" [-u] udprelay mode to supprot udp traffic\n"); - printf(" only available in local and server modes\n"); + printf(" not available in redir mode\n"); + printf(" [-L :] setup a local port forwarding tunnel\n"); + printf(" only available in tunnel mode\n"); printf(" [-v] verbose mode, debug output in console\n"); printf("\n"); }