shadowsocksr-libev: add support for read listening mode from config

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2021-05-10 01:58:14 +08:00
parent 0c4a35392b
commit d6c9ef9ae1
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
52 changed files with 16526 additions and 16636 deletions

View File

@ -1,16 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2021 ImmortalWrt
# <https://immortalwrt.org>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
# Copyright (C) 2017-2020 Yousong Zhou <yszhou4tech@gmail.com>
# Copyright (C) 2018 Lean <coolsnowwolf@gmail.com>
# Copyright (C) 2021 ImmortalWrt.org
include $(TOPDIR)/rules.mk
PKG_NAME:=shadowsocksr-libev
PKG_VERSION:=2.5.6
PKG_RELEASE:=7
PKG_RELEASE:=8
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/shadowsocksrr/shadowsocksr-libev

View File

@ -0,0 +1,40 @@
diff --git a/src/jconf.c b/src/jconf.c
index 710f70d..1613e20 100644
--- a/src/jconf.c
+++ b/src/jconf.c
@@ -259,6 +259,19 @@ read_jconf(const char *file)
conf.server_legacy.obfs = to_string(value);
} else if (strcmp(name, "obfs_param") == 0) { // SSR
conf.server_legacy.obfs_param = to_string(value);
+ } else if (strcmp(name, "mode") == 0) {
+ char *mode_str = to_string(value);
+
+ if (strcmp(mode_str, "tcp_only") == 0)
+ conf.mode = TCP_ONLY;
+ else if (strcmp(mode_str, "tcp_and_udp") == 0)
+ conf.mode = TCP_AND_UDP;
+ else if (strcmp(mode_str, "udp_only") == 0)
+ conf.mode = UDP_ONLY;
+ else
+ LOGI("ignore unknown mode: %s, use tcp_only as fallback",
+ mode_str);
+ ss_free(mode_str);
} else {
match = 0;
}
diff --git a/src/redir.c b/src/redir.c
index feafd5e..64521a1 100644
--- a/src/redir.c
+++ b/src/redir.c
@@ -1252,7 +1252,10 @@ main(int argc, char **argv)
if (user == NULL) {
user = conf->user;
}
- if (mtu == 0) {
+ if (mode == TCP_ONLY) {
+ mode = conf->mode;
+ }
+ if (mtu == 0) {
mtu = conf->mtu;
}
if (mptcp == 0) {

View File

@ -0,0 +1,55 @@
VERSION_INFO = 2:0:0
AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE
AM_CFLAGS += $(PTHREAD_CFLAGS)
if !USE_SYSTEM_SHARED_LIB
AM_CFLAGS += -I$(top_srcdir)/libev
AM_CFLAGS += -I$(top_srcdir)/libudns
AM_CFLAGS += -I$(top_srcdir)/libsodium/src/libsodium/include
endif
AM_CFLAGS += -I$(top_srcdir)/libipset/include
AM_CFLAGS += -I$(top_srcdir)/libcork/include
AM_CFLAGS += $(LIBPCRE_CFLAGS)
SS_COMMON_LIBS = $(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la \
$(INET_NTOP_LIB) $(LIBPCRE_LIBS)
if USE_SYSTEM_SHARED_LIB
SS_COMMON_LIBS += -lev -lsodium -lm
else
SS_COMMON_LIBS += $(top_builddir)/libev/libev.la \
$(top_builddir)/libsodium/src/libsodium/libsodium.la
endif
bin_PROGRAMS = ss-server ss-check
sni_src = http.c \
tls.c \
rule.c
ss_check_SOURCES = check.c
ss_server_SOURCES = utils.c \
netutils.c \
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
acl.c \
resolv.c \
server.c \
$(sni_src)
ss_check_LDADD = $(SS_COMMON_LIBS)
ss_server_LDADD = $(SS_COMMON_LIBS)
if USE_SYSTEM_SHARED_LIB
ss_server_LDADD += -ludns
else
ss_server_LDADD += $(top_builddir)/libudns/libudns.la
endif
ss_check_CFLAGS = $(AM_CFLAGS)
ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE

View File

@ -0,0 +1,919 @@
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@USE_SYSTEM_SHARED_LIB_FALSE@am__append_1 = -I$(top_srcdir)/libev \
@USE_SYSTEM_SHARED_LIB_FALSE@ -I$(top_srcdir)/libudns \
@USE_SYSTEM_SHARED_LIB_FALSE@ -I$(top_srcdir)/libsodium/src/libsodium/include
@USE_SYSTEM_SHARED_LIB_TRUE@am__append_2 = -lev -lsodium -lm
@USE_SYSTEM_SHARED_LIB_FALSE@am__append_3 = $(top_builddir)/libev/libev.la \
@USE_SYSTEM_SHARED_LIB_FALSE@ $(top_builddir)/libsodium/src/libsodium/libsodium.la
bin_PROGRAMS = ss-server$(EXEEXT) ss-check$(EXEEXT)
@USE_SYSTEM_SHARED_LIB_TRUE@am__append_4 = -ludns
@USE_SYSTEM_SHARED_LIB_FALSE@am__append_5 = $(top_builddir)/libudns/libudns.la
subdir = server
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
$(top_srcdir)/m4/ax_tls.m4 $(top_srcdir)/m4/inet_ntop.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mbedtls.m4 \
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/pcre.m4 \
$(top_srcdir)/m4/polarssl.m4 \
$(top_srcdir)/m4/stack-protector.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
am_ss_check_OBJECTS = ss_check-check.$(OBJEXT)
ss_check_OBJECTS = $(am_ss_check_OBJECTS)
am__DEPENDENCIES_1 =
am__DEPENDENCIES_2 = $(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__append_3)
ss_check_DEPENDENCIES = $(am__DEPENDENCIES_2)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
ss_check_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_check_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
am__objects_1 = ss_server-http.$(OBJEXT) ss_server-tls.$(OBJEXT) \
ss_server-rule.$(OBJEXT)
am_ss_server_OBJECTS = ss_server-utils.$(OBJEXT) \
ss_server-netutils.$(OBJEXT) ss_server-jconf.$(OBJEXT) \
ss_server-json.$(OBJEXT) ss_server-encrypt.$(OBJEXT) \
ss_server-udprelay.$(OBJEXT) ss_server-cache.$(OBJEXT) \
ss_server-acl.$(OBJEXT) ss_server-resolv.$(OBJEXT) \
ss_server-server.$(OBJEXT) $(am__objects_1)
ss_server_OBJECTS = $(am_ss_server_OBJECTS)
ss_server_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
$(am__append_5)
ss_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_server_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/auto/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(ss_check_SOURCES) $(ss_server_SOURCES)
DIST_SOURCES = $(ss_check_SOURCES) $(ss_server_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/auto/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ASCIIDOC = @ASCIIDOC@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
GZIP = @GZIP@
INET_NTOP_LIB = @INET_NTOP_LIB@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBPCRE = @LIBPCRE@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MV = @MV@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PCRE_CONFIG = @PCRE_CONFIG@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
XMLTO = @XMLTO@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pcre_pcreh = @pcre_pcreh@
pcreh = @pcreh@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
VERSION_INFO = 2:0:0
AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations \
-fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE \
$(PTHREAD_CFLAGS) $(am__append_1) \
-I$(top_srcdir)/libipset/include \
-I$(top_srcdir)/libcork/include $(LIBPCRE_CFLAGS)
SS_COMMON_LIBS = $(top_builddir)/libipset/libipset.la \
$(top_builddir)/libcork/libcork.la $(INET_NTOP_LIB) \
$(LIBPCRE_LIBS) $(am__append_2) $(am__append_3)
sni_src = http.c \
tls.c \
rule.c
ss_check_SOURCES = check.c
ss_server_SOURCES = utils.c \
netutils.c \
jconf.c \
json.c \
encrypt.c \
udprelay.c \
cache.c \
acl.c \
resolv.c \
server.c \
$(sni_src)
ss_check_LDADD = $(SS_COMMON_LIBS)
ss_server_LDADD = $(SS_COMMON_LIBS) $(am__append_4) $(am__append_5)
ss_check_CFLAGS = $(AM_CFLAGS)
ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign server/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign server/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
ss-check$(EXEEXT): $(ss_check_OBJECTS) $(ss_check_DEPENDENCIES) $(EXTRA_ss_check_DEPENDENCIES)
@rm -f ss-check$(EXEEXT)
$(AM_V_CCLD)$(ss_check_LINK) $(ss_check_OBJECTS) $(ss_check_LDADD) $(LIBS)
ss-server$(EXEEXT): $(ss_server_OBJECTS) $(ss_server_DEPENDENCIES) $(EXTRA_ss_server_DEPENDENCIES)
@rm -f ss-server$(EXEEXT)
$(AM_V_CCLD)$(ss_server_LINK) $(ss_server_OBJECTS) $(ss_server_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_check-check.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-acl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-cache.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-encrypt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-http.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-jconf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-json.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-netutils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-resolv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-rule.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-server.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_server-tls.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@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
ss_check-check.o: check.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_check_CFLAGS) $(CFLAGS) -MT ss_check-check.o -MD -MP -MF $(DEPDIR)/ss_check-check.Tpo -c -o ss_check-check.o `test -f 'check.c' || echo '$(srcdir)/'`check.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_check-check.Tpo $(DEPDIR)/ss_check-check.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check.c' object='ss_check-check.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_check_CFLAGS) $(CFLAGS) -c -o ss_check-check.o `test -f 'check.c' || echo '$(srcdir)/'`check.c
ss_check-check.obj: check.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_check_CFLAGS) $(CFLAGS) -MT ss_check-check.obj -MD -MP -MF $(DEPDIR)/ss_check-check.Tpo -c -o ss_check-check.obj `if test -f 'check.c'; then $(CYGPATH_W) 'check.c'; else $(CYGPATH_W) '$(srcdir)/check.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_check-check.Tpo $(DEPDIR)/ss_check-check.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check.c' object='ss_check-check.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_check_CFLAGS) $(CFLAGS) -c -o ss_check-check.obj `if test -f 'check.c'; then $(CYGPATH_W) 'check.c'; else $(CYGPATH_W) '$(srcdir)/check.c'; fi`
ss_server-utils.o: utils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-utils.o -MD -MP -MF $(DEPDIR)/ss_server-utils.Tpo -c -o ss_server-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-utils.Tpo $(DEPDIR)/ss_server-utils.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='ss_server-utils.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c
ss_server-utils.obj: utils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-utils.obj -MD -MP -MF $(DEPDIR)/ss_server-utils.Tpo -c -o ss_server-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-utils.Tpo $(DEPDIR)/ss_server-utils.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='utils.c' object='ss_server-utils.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi`
ss_server-netutils.o: netutils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-netutils.o -MD -MP -MF $(DEPDIR)/ss_server-netutils.Tpo -c -o ss_server-netutils.o `test -f 'netutils.c' || echo '$(srcdir)/'`netutils.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-netutils.Tpo $(DEPDIR)/ss_server-netutils.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netutils.c' object='ss_server-netutils.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-netutils.o `test -f 'netutils.c' || echo '$(srcdir)/'`netutils.c
ss_server-netutils.obj: netutils.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-netutils.obj -MD -MP -MF $(DEPDIR)/ss_server-netutils.Tpo -c -o ss_server-netutils.obj `if test -f 'netutils.c'; then $(CYGPATH_W) 'netutils.c'; else $(CYGPATH_W) '$(srcdir)/netutils.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-netutils.Tpo $(DEPDIR)/ss_server-netutils.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netutils.c' object='ss_server-netutils.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-netutils.obj `if test -f 'netutils.c'; then $(CYGPATH_W) 'netutils.c'; else $(CYGPATH_W) '$(srcdir)/netutils.c'; fi`
ss_server-jconf.o: jconf.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-jconf.o -MD -MP -MF $(DEPDIR)/ss_server-jconf.Tpo -c -o ss_server-jconf.o `test -f 'jconf.c' || echo '$(srcdir)/'`jconf.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-jconf.Tpo $(DEPDIR)/ss_server-jconf.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jconf.c' object='ss_server-jconf.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-jconf.o `test -f 'jconf.c' || echo '$(srcdir)/'`jconf.c
ss_server-jconf.obj: jconf.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-jconf.obj -MD -MP -MF $(DEPDIR)/ss_server-jconf.Tpo -c -o ss_server-jconf.obj `if test -f 'jconf.c'; then $(CYGPATH_W) 'jconf.c'; else $(CYGPATH_W) '$(srcdir)/jconf.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-jconf.Tpo $(DEPDIR)/ss_server-jconf.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jconf.c' object='ss_server-jconf.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-jconf.obj `if test -f 'jconf.c'; then $(CYGPATH_W) 'jconf.c'; else $(CYGPATH_W) '$(srcdir)/jconf.c'; fi`
ss_server-json.o: json.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-json.o -MD -MP -MF $(DEPDIR)/ss_server-json.Tpo -c -o ss_server-json.o `test -f 'json.c' || echo '$(srcdir)/'`json.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-json.Tpo $(DEPDIR)/ss_server-json.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='json.c' object='ss_server-json.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-json.o `test -f 'json.c' || echo '$(srcdir)/'`json.c
ss_server-json.obj: json.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-json.obj -MD -MP -MF $(DEPDIR)/ss_server-json.Tpo -c -o ss_server-json.obj `if test -f 'json.c'; then $(CYGPATH_W) 'json.c'; else $(CYGPATH_W) '$(srcdir)/json.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-json.Tpo $(DEPDIR)/ss_server-json.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='json.c' object='ss_server-json.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-json.obj `if test -f 'json.c'; then $(CYGPATH_W) 'json.c'; else $(CYGPATH_W) '$(srcdir)/json.c'; fi`
ss_server-encrypt.o: encrypt.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-encrypt.o -MD -MP -MF $(DEPDIR)/ss_server-encrypt.Tpo -c -o ss_server-encrypt.o `test -f 'encrypt.c' || echo '$(srcdir)/'`encrypt.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-encrypt.Tpo $(DEPDIR)/ss_server-encrypt.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='encrypt.c' object='ss_server-encrypt.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-encrypt.o `test -f 'encrypt.c' || echo '$(srcdir)/'`encrypt.c
ss_server-encrypt.obj: encrypt.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-encrypt.obj -MD -MP -MF $(DEPDIR)/ss_server-encrypt.Tpo -c -o ss_server-encrypt.obj `if test -f 'encrypt.c'; then $(CYGPATH_W) 'encrypt.c'; else $(CYGPATH_W) '$(srcdir)/encrypt.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-encrypt.Tpo $(DEPDIR)/ss_server-encrypt.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='encrypt.c' object='ss_server-encrypt.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-encrypt.obj `if test -f 'encrypt.c'; then $(CYGPATH_W) 'encrypt.c'; else $(CYGPATH_W) '$(srcdir)/encrypt.c'; fi`
ss_server-udprelay.o: udprelay.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-udprelay.o -MD -MP -MF $(DEPDIR)/ss_server-udprelay.Tpo -c -o ss_server-udprelay.o `test -f 'udprelay.c' || echo '$(srcdir)/'`udprelay.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-udprelay.Tpo $(DEPDIR)/ss_server-udprelay.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='udprelay.c' object='ss_server-udprelay.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-udprelay.o `test -f 'udprelay.c' || echo '$(srcdir)/'`udprelay.c
ss_server-udprelay.obj: udprelay.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-udprelay.obj -MD -MP -MF $(DEPDIR)/ss_server-udprelay.Tpo -c -o ss_server-udprelay.obj `if test -f 'udprelay.c'; then $(CYGPATH_W) 'udprelay.c'; else $(CYGPATH_W) '$(srcdir)/udprelay.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-udprelay.Tpo $(DEPDIR)/ss_server-udprelay.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='udprelay.c' object='ss_server-udprelay.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-udprelay.obj `if test -f 'udprelay.c'; then $(CYGPATH_W) 'udprelay.c'; else $(CYGPATH_W) '$(srcdir)/udprelay.c'; fi`
ss_server-cache.o: cache.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-cache.o -MD -MP -MF $(DEPDIR)/ss_server-cache.Tpo -c -o ss_server-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-cache.Tpo $(DEPDIR)/ss_server-cache.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='ss_server-cache.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c
ss_server-cache.obj: cache.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-cache.obj -MD -MP -MF $(DEPDIR)/ss_server-cache.Tpo -c -o ss_server-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-cache.Tpo $(DEPDIR)/ss_server-cache.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='ss_server-cache.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi`
ss_server-acl.o: acl.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-acl.o -MD -MP -MF $(DEPDIR)/ss_server-acl.Tpo -c -o ss_server-acl.o `test -f 'acl.c' || echo '$(srcdir)/'`acl.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-acl.Tpo $(DEPDIR)/ss_server-acl.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acl.c' object='ss_server-acl.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-acl.o `test -f 'acl.c' || echo '$(srcdir)/'`acl.c
ss_server-acl.obj: acl.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-acl.obj -MD -MP -MF $(DEPDIR)/ss_server-acl.Tpo -c -o ss_server-acl.obj `if test -f 'acl.c'; then $(CYGPATH_W) 'acl.c'; else $(CYGPATH_W) '$(srcdir)/acl.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-acl.Tpo $(DEPDIR)/ss_server-acl.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acl.c' object='ss_server-acl.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-acl.obj `if test -f 'acl.c'; then $(CYGPATH_W) 'acl.c'; else $(CYGPATH_W) '$(srcdir)/acl.c'; fi`
ss_server-resolv.o: resolv.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-resolv.o -MD -MP -MF $(DEPDIR)/ss_server-resolv.Tpo -c -o ss_server-resolv.o `test -f 'resolv.c' || echo '$(srcdir)/'`resolv.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-resolv.Tpo $(DEPDIR)/ss_server-resolv.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resolv.c' object='ss_server-resolv.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-resolv.o `test -f 'resolv.c' || echo '$(srcdir)/'`resolv.c
ss_server-resolv.obj: resolv.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-resolv.obj -MD -MP -MF $(DEPDIR)/ss_server-resolv.Tpo -c -o ss_server-resolv.obj `if test -f 'resolv.c'; then $(CYGPATH_W) 'resolv.c'; else $(CYGPATH_W) '$(srcdir)/resolv.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-resolv.Tpo $(DEPDIR)/ss_server-resolv.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='resolv.c' object='ss_server-resolv.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-resolv.obj `if test -f 'resolv.c'; then $(CYGPATH_W) 'resolv.c'; else $(CYGPATH_W) '$(srcdir)/resolv.c'; fi`
ss_server-server.o: server.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-server.o -MD -MP -MF $(DEPDIR)/ss_server-server.Tpo -c -o ss_server-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-server.Tpo $(DEPDIR)/ss_server-server.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='ss_server-server.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c
ss_server-server.obj: server.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-server.obj -MD -MP -MF $(DEPDIR)/ss_server-server.Tpo -c -o ss_server-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-server.Tpo $(DEPDIR)/ss_server-server.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='ss_server-server.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(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_server-http.o: http.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-http.o -MD -MP -MF $(DEPDIR)/ss_server-http.Tpo -c -o ss_server-http.o `test -f 'http.c' || echo '$(srcdir)/'`http.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-http.Tpo $(DEPDIR)/ss_server-http.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http.c' object='ss_server-http.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-http.o `test -f 'http.c' || echo '$(srcdir)/'`http.c
ss_server-http.obj: http.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-http.obj -MD -MP -MF $(DEPDIR)/ss_server-http.Tpo -c -o ss_server-http.obj `if test -f 'http.c'; then $(CYGPATH_W) 'http.c'; else $(CYGPATH_W) '$(srcdir)/http.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-http.Tpo $(DEPDIR)/ss_server-http.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http.c' object='ss_server-http.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-http.obj `if test -f 'http.c'; then $(CYGPATH_W) 'http.c'; else $(CYGPATH_W) '$(srcdir)/http.c'; fi`
ss_server-tls.o: tls.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-tls.o -MD -MP -MF $(DEPDIR)/ss_server-tls.Tpo -c -o ss_server-tls.o `test -f 'tls.c' || echo '$(srcdir)/'`tls.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-tls.Tpo $(DEPDIR)/ss_server-tls.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls.c' object='ss_server-tls.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-tls.o `test -f 'tls.c' || echo '$(srcdir)/'`tls.c
ss_server-tls.obj: tls.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-tls.obj -MD -MP -MF $(DEPDIR)/ss_server-tls.Tpo -c -o ss_server-tls.obj `if test -f 'tls.c'; then $(CYGPATH_W) 'tls.c'; else $(CYGPATH_W) '$(srcdir)/tls.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-tls.Tpo $(DEPDIR)/ss_server-tls.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tls.c' object='ss_server-tls.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-tls.obj `if test -f 'tls.c'; then $(CYGPATH_W) 'tls.c'; else $(CYGPATH_W) '$(srcdir)/tls.c'; fi`
ss_server-rule.o: rule.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-rule.o -MD -MP -MF $(DEPDIR)/ss_server-rule.Tpo -c -o ss_server-rule.o `test -f 'rule.c' || echo '$(srcdir)/'`rule.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-rule.Tpo $(DEPDIR)/ss_server-rule.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rule.c' object='ss_server-rule.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-rule.o `test -f 'rule.c' || echo '$(srcdir)/'`rule.c
ss_server-rule.obj: rule.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -MT ss_server-rule.obj -MD -MP -MF $(DEPDIR)/ss_server-rule.Tpo -c -o ss_server-rule.obj `if test -f 'rule.c'; then $(CYGPATH_W) 'rule.c'; else $(CYGPATH_W) '$(srcdir)/rule.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_server-rule.Tpo $(DEPDIR)/ss_server-rule.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rule.c' object='ss_server-rule.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_server_CFLAGS) $(CFLAGS) -c -o ss_server-rule.obj `if test -f 'rule.c'; then $(CYGPATH_W) 'rule.c'; else $(CYGPATH_W) '$(srcdir)/rule.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,3 @@
# server
`ss-server` and `ss-check` from https://github.com/ywb94/shadowsocks-libev

View File

@ -0,0 +1,597 @@
/*
* acl.c - Manage the ACL (Access Control List)
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <ipset/ipset.h>
#include <ctype.h>
#include "rule.h"
#include "utils.h"
#include "cache.h"
#include "acl.h"
static struct ip_set white_list_ipv4;
static struct ip_set white_list_ipv6;
static struct ip_set black_list_ipv4;
static struct ip_set black_list_ipv6;
static struct cork_dllist black_list_rules;
static struct cork_dllist white_list_rules;
static int acl_mode = BLACK_LIST;
static struct cache *block_list;
static struct ip_set outbound_block_list_ipv4;
static struct ip_set outbound_block_list_ipv6;
static struct cork_dllist outbound_block_list_rules;
#ifdef __linux__
#include <unistd.h>
#include <stdio.h>
#define NO_FIREWALL_MODE 0
#define IPTABLES_MODE 1
#define FIREWALLD_MODE 2
static FILE *shell_stdin;
static int mode = NO_FIREWALL_MODE;
static char chain_name[64];
static char *iptables_init_chain =
"iptables -N %s; iptables -F %s; iptables -A OUTPUT -p tcp --tcp-flags RST RST -j %s";
static char *iptables_remove_chain =
"iptables -D OUTPUT -p tcp --tcp-flags RST RST -j %s; iptables -F %s; iptables -X %s";
static char *iptables_add_rule = "iptables -A %s -d %s -j DROP";
static char *iptables_remove_rule = "iptables -D %s -d %s -j DROP";
static char *ip6tables_init_chain =
"ip6tables -N %s; ip6tables -F %s; ip6tables -A OUTPUT -p tcp --tcp-flags RST RST -j %s";
static char *ip6tables_remove_chain =
"ip6tables -D OUTPUT -p tcp --tcp-flags RST RST -j %s; ip6tables -F %s; ip6tables -X %s";
static char *ip6tables_add_rule = "ip6tables -A %s -d %s -j DROP";
static char *ip6tables_remove_rule = "ip6tables -D %s -d %s -j DROP";
static char *firewalld_init_chain =
"firewall-cmd --direct --add-chain ipv4 filter %s; \
firewall-cmd --direct --passthrough ipv4 -F %s; \
firewall-cmd --direct --passthrough ipv4 -A OUTPUT -p tcp --tcp-flags RST RST -j %s";
static char *firewalld_remove_chain =
"firewall-cmd --direct --passthrough ipv4 -D OUTPUT -p tcp --tcp-flags RST RST -j %s; \
firewall-cmd --direct --passthrough ipv4 -F %s; \
firewall-cmd --direct --remove-chain ipv4 filter %s";
static char *firewalld_add_rule = "firewall-cmd --direct --passthrough ipv4 -A %s -d %s -j DROP";
static char *firewalld_remove_rule = "firewall-cmd --direct --passthrough ipv4 -D %s -d %s -j DROP";
static char *firewalld6_init_chain =
"firewall-cmd --direct --add-chain ipv6 filter %s; \
firewall-cmd --direct --passthrough ipv6 -F %s; \
firewall-cmd --direct --passthrough ipv6 -A OUTPUT -p tcp --tcp-flags RST RST -j %s";
static char *firewalld6_remove_chain =
"firewall-cmd --direct --passthrough ipv6 -D OUTPUT -p tcp --tcp-flags RST RST -j %s; \
firewall-cmd --direct --passthrough ipv6 -F %s; \
firewall-cmd --direct --remove-chain ipv6 filter %s";
static char *firewalld6_add_rule = "firewall-cmd --direct --passthrough ipv6 -A %s -d %s -j DROP";
static char *firewalld6_remove_rule = "firewall-cmd --direct --passthrough ipv6 -D %s -d %s -j DROP";
static int
run_cmd(const char *cmd)
{
int ret = 0;
char cmdstring[256];
sprintf(cmdstring, "%s\n", cmd);
size_t len = strlen(cmdstring);
if (shell_stdin != NULL) {
ret = fwrite(cmdstring, 1, len, shell_stdin);
fflush(shell_stdin);
}
return ret == len;
}
static int
init_firewall()
{
int ret = 0;
char cli[256];
FILE *fp;
if (getuid() != 0)
return -1;
sprintf(cli, "firewall-cmd --version 2>&1");
fp = popen(cli, "r");
if (fp == NULL)
return -1;
if (pclose(fp) == 0) {
mode = FIREWALLD_MODE;
} else {
/* Check whether we have permission to operate iptables.
* Note that checking `iptables --version` is insufficient:
* eg, running within a child user namespace.
*/
sprintf(cli, "iptables -L 2>&1");
fp = popen(cli, "r");
if (fp == NULL)
return -1;
if (pclose(fp) == 0)
mode = IPTABLES_MODE;
}
sprintf(chain_name, "SHADOWSOCKS_LIBEV_%d", getpid());
if (mode == FIREWALLD_MODE) {
sprintf(cli, firewalld6_init_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
sprintf(cli, firewalld_init_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
} else if (mode == IPTABLES_MODE) {
sprintf(cli, ip6tables_init_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
sprintf(cli, iptables_init_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
}
shell_stdin = popen("/bin/sh", "w");
return ret;
}
static int
reset_firewall()
{
int ret = 0;
char cli[256];
if (getuid() != 0)
return -1;
if (mode == IPTABLES_MODE) {
sprintf(cli, ip6tables_remove_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
sprintf(cli, iptables_remove_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
} else if (mode == FIREWALLD_MODE) {
sprintf(cli, firewalld6_remove_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
sprintf(cli, firewalld_remove_chain, chain_name, chain_name, chain_name);
ret |= system(cli);
}
if (shell_stdin != NULL) {
run_cmd("exit 0");
pclose(shell_stdin);
}
return ret;
}
static int
set_firewall_rule(char *addr, int add)
{
char cli[256];
struct cork_ip ip;
if (getuid() != 0)
return -1;
if (cork_ip_init(&ip, addr))
return -1;
if (add) {
if (mode == IPTABLES_MODE)
sprintf(cli, ip.version == 4 ? iptables_add_rule : ip6tables_add_rule,
chain_name, addr);
else if (mode == FIREWALLD_MODE)
sprintf(cli, ip.version == 4 ? firewalld_add_rule : firewalld6_add_rule,
chain_name, addr);
return run_cmd(cli);
} else {
if (mode == IPTABLES_MODE)
sprintf(cli, ip.version == 4 ? iptables_remove_rule : ip6tables_remove_rule,
chain_name, addr);
else if (mode == FIREWALLD_MODE)
sprintf(cli, ip.version == 4 ? firewalld_remove_rule : firewalld6_remove_rule,
chain_name, addr);
return run_cmd(cli);
}
return 0;
}
static void
free_firewall_rule(void *key, void *element)
{
if (key == NULL)
return;
char *addr = (char *)key;
set_firewall_rule(addr, 0);
ss_free(element);
}
#endif
void
init_block_list(int firewall)
{
// Initialize cache
#ifdef __linux__
if (firewall)
init_firewall();
else
mode = NO_FIREWALL_MODE;
cache_create(&block_list, 256, free_firewall_rule);
#else
cache_create(&block_list, 256, NULL);
#endif
}
void
free_block_list()
{
#ifdef __linux__
if (mode != NO_FIREWALL_MODE)
reset_firewall();
#endif
cache_clear(block_list, 0); // Remove all items
}
int
remove_from_block_list(char *addr)
{
size_t addr_len = strlen(addr);
return cache_remove(block_list, addr, addr_len);
}
void
clear_block_list()
{
cache_clear(block_list, 3600); // Clear items older than 1 hour
}
int
check_block_list(char *addr)
{
size_t addr_len = strlen(addr);
if (cache_key_exist(block_list, addr, addr_len)) {
int *count = NULL;
cache_lookup(block_list, addr, addr_len, &count);
if (count != NULL && *count > MAX_TRIES)
return 1;
}
return 0;
}
int
update_block_list(char *addr, int err_level)
{
size_t addr_len = strlen(addr);
if (cache_key_exist(block_list, addr, addr_len)) {
int *count = NULL;
cache_lookup(block_list, addr, addr_len, &count);
if (count != NULL) {
if (*count > MAX_TRIES)
return 1;
(*count) += err_level;
}
} else if (err_level > 0) {
int *count = (int *)ss_malloc(sizeof(int));
*count = 1;
cache_insert(block_list, addr, addr_len, count);
#ifdef __linux__
if (mode != NO_FIREWALL_MODE)
set_firewall_rule(addr, 1);
#endif
}
return 0;
}
static void
parse_addr_cidr(const char *str, char *host, int *cidr)
{
int ret = -1, n = 0;
char *pch;
pch = strchr(str, '/');
while (pch != NULL) {
n++;
ret = pch - str;
pch = strchr(pch + 1, '/');
}
if (ret == -1) {
strcpy(host, str);
*cidr = -1;
} else {
memcpy(host, str, ret);
host[ret] = '\0';
*cidr = atoi(str + ret + 1);
}
}
char *
trimwhitespace(char *str)
{
char *end;
// Trim leading space
while (isspace(*str))
str++;
if (*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while (end > str && isspace(*end))
end--;
// Write new null terminator
*(end + 1) = 0;
return str;
}
int
init_acl(const char *path)
{
// initialize ipset
ipset_init_library();
ipset_init(&white_list_ipv4);
ipset_init(&white_list_ipv6);
ipset_init(&black_list_ipv4);
ipset_init(&black_list_ipv6);
ipset_init(&outbound_block_list_ipv4);
ipset_init(&outbound_block_list_ipv6);
cork_dllist_init(&black_list_rules);
cork_dllist_init(&white_list_rules);
cork_dllist_init(&outbound_block_list_rules);
struct ip_set *list_ipv4 = &black_list_ipv4;
struct ip_set *list_ipv6 = &black_list_ipv6;
struct cork_dllist *rules = &black_list_rules;
FILE *f = fopen(path, "r");
if (f == NULL) {
LOGE("Invalid acl path.");
return -1;
}
char buf[257];
while (!feof(f))
if (fgets(buf, 256, f)) {
// Trim the newline
int len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n') {
buf[len - 1] = '\0';
}
char *line = trimwhitespace(buf);
// Skip comments
if (line[0] == '#') {
continue;
}
if (strlen(line) == 0) {
continue;
}
if (strcmp(line, "[outbound_block_list]") == 0) {
list_ipv4 = &outbound_block_list_ipv4;
list_ipv6 = &outbound_block_list_ipv6;
rules = &outbound_block_list_rules;
continue;
} else if (strcmp(line, "[black_list]") == 0
|| strcmp(line, "[bypass_list]") == 0) {
list_ipv4 = &black_list_ipv4;
list_ipv6 = &black_list_ipv6;
rules = &black_list_rules;
continue;
} else if (strcmp(line, "[white_list]") == 0
|| strcmp(line, "[proxy_list]") == 0) {
list_ipv4 = &white_list_ipv4;
list_ipv6 = &white_list_ipv6;
rules = &white_list_rules;
continue;
} else if (strcmp(line, "[reject_all]") == 0
|| strcmp(line, "[bypass_all]") == 0) {
acl_mode = WHITE_LIST;
continue;
} else if (strcmp(line, "[accept_all]") == 0
|| strcmp(line, "[proxy_all]") == 0) {
acl_mode = BLACK_LIST;
continue;
}
char host[257];
int cidr;
parse_addr_cidr(line, host, &cidr);
struct cork_ip addr;
int err = cork_ip_init(&addr, host);
if (!err) {
if (addr.version == 4) {
if (cidr >= 0) {
ipset_ipv4_add_network(list_ipv4, &(addr.ip.v4), cidr);
} else {
ipset_ipv4_add(list_ipv4, &(addr.ip.v4));
}
} else if (addr.version == 6) {
if (cidr >= 0) {
ipset_ipv6_add_network(list_ipv6, &(addr.ip.v6), cidr);
} else {
ipset_ipv6_add(list_ipv6, &(addr.ip.v6));
}
}
} else {
rule_t *rule = new_rule();
accept_rule_arg(rule, line);
init_rule(rule);
add_rule(rules, rule);
}
}
fclose(f);
return 0;
}
void
free_rules(struct cork_dllist *rules)
{
struct cork_dllist_item *iter;
while ((iter = cork_dllist_head(rules)) != NULL) {
rule_t *rule = cork_container_of(iter, rule_t, entries);
remove_rule(rule);
}
}
void
free_acl(void)
{
ipset_done(&black_list_ipv4);
ipset_done(&black_list_ipv6);
ipset_done(&white_list_ipv4);
ipset_done(&white_list_ipv6);
free_rules(&black_list_rules);
free_rules(&white_list_rules);
}
int
get_acl_mode(void)
{
return acl_mode;
}
/*
* Return 0, if not match.
* Return 1, if match black list.
* Return -1, if match white list.
*/
int
acl_match_host(const char *host)
{
struct cork_ip addr;
int ret = 0;
int err = cork_ip_init(&addr, host);
if (err) {
int host_len = strlen(host);
if (lookup_rule(&black_list_rules, host, host_len) != NULL)
ret = 1;
else if (lookup_rule(&white_list_rules, host, host_len) != NULL)
ret = -1;
return ret;
}
if (addr.version == 4) {
if (ipset_contains_ipv4(&black_list_ipv4, &(addr.ip.v4)))
ret = 1;
else if (ipset_contains_ipv4(&white_list_ipv4, &(addr.ip.v4)))
ret = -1;
} else if (addr.version == 6) {
if (ipset_contains_ipv6(&black_list_ipv6, &(addr.ip.v6)))
ret = 1;
else if (ipset_contains_ipv6(&white_list_ipv6, &(addr.ip.v6)))
ret = -1;
}
return ret;
}
int
acl_add_ip(const char *ip)
{
struct cork_ip addr;
int err = cork_ip_init(&addr, ip);
if (err) {
return -1;
}
if (addr.version == 4) {
ipset_ipv4_add(&black_list_ipv4, &(addr.ip.v4));
} else if (addr.version == 6) {
ipset_ipv6_add(&black_list_ipv6, &(addr.ip.v6));
}
return 0;
}
int
acl_remove_ip(const char *ip)
{
struct cork_ip addr;
int err = cork_ip_init(&addr, ip);
if (err) {
return -1;
}
if (addr.version == 4) {
ipset_ipv4_remove(&black_list_ipv4, &(addr.ip.v4));
} else if (addr.version == 6) {
ipset_ipv6_remove(&black_list_ipv6, &(addr.ip.v6));
}
return 0;
}
/*
* Return 0, if not match.
* Return 1, if match black list.
*/
int
outbound_block_match_host(const char *host)
{
struct cork_ip addr;
int ret = 0;
int err = cork_ip_init(&addr, host);
if (err) {
int host_len = strlen(host);
if (lookup_rule(&outbound_block_list_rules, host, host_len) != NULL)
ret = 1;
return ret;
}
if (addr.version == 4) {
if (ipset_contains_ipv4(&outbound_block_list_ipv4, &(addr.ip.v4)))
ret = 1;
} else if (addr.version == 6) {
if (ipset_contains_ipv6(&outbound_block_list_ipv6, &(addr.ip.v6)))
ret = 1;
}
return ret;
}

View File

@ -0,0 +1,53 @@
/*
* acl.h - Define the ACL interface
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _ACL_H
#define _ACL_H
#define BLACK_LIST 0
#define WHITE_LIST 1
#define MAX_TRIES 64
#define MALICIOUS 8
#define SUSPICIOUS 4
#define BAD 2
#define MALFORMED 1
int init_acl(const char *path);
void free_acl(void);
void clear_block_list(void);
int acl_match_host(const char *ip);
int acl_add_ip(const char *ip);
int acl_remove_ip(const char *ip);
int get_acl_mode(void);
void init_block_list(int firewall);
void free_block_list();
int check_block_list(char *addr);
int update_block_list(char *addr, int err_level);
int remove_from_block_list(char *addr);
int outbound_block_match_host(const char *host);
#endif // _ACL_H

View File

@ -0,0 +1,993 @@
#include "auth.h"
static int auth_simple_pack_unit_size = 2000;
typedef int (*hmac_with_key_func)(char *auth, char *msg, int msg_len, uint8_t *auth_key, int key_len);
typedef int (*hash_func)(char *auth, char *msg, int msg_len);
typedef struct auth_simple_global_data {
uint8_t local_client_id[8];
uint32_t connection_id;
}auth_simple_global_data;
typedef struct auth_simple_local_data {
int has_sent_header;
char * recv_buffer;
int recv_buffer_size;
uint32_t recv_id;
uint32_t pack_id;
char * salt;
uint8_t * user_key;
char uid[4];
int user_key_len;
hmac_with_key_func hmac;
hash_func hash;
int hash_len;
}auth_simple_local_data;
void auth_simple_local_data_init(auth_simple_local_data* local) {
local->has_sent_header = 0;
local->recv_buffer = (char*)malloc(16384);
local->recv_buffer_size = 0;
local->recv_id = 1;
local->pack_id = 1;
local->salt = "";
local->user_key = 0;
local->user_key_len = 0;
local->hmac = 0;
local->hash = 0;
local->hash_len = 0;
local->salt = "";
}
void * auth_simple_init_data() {
auth_simple_global_data *global = (auth_simple_global_data*)malloc(sizeof(auth_simple_global_data));
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
return global;
}
obfs * auth_simple_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(auth_simple_local_data));
auth_simple_local_data_init((auth_simple_local_data*)self->l_data);
return self;
}
obfs * auth_aes128_md5_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(auth_simple_local_data));
auth_simple_local_data_init((auth_simple_local_data*)self->l_data);
((auth_simple_local_data*)self->l_data)->hmac = ss_md5_hmac_with_key;
((auth_simple_local_data*)self->l_data)->hash = ss_md5_hash_func;
((auth_simple_local_data*)self->l_data)->hash_len = 16;
((auth_simple_local_data*)self->l_data)->salt = "auth_aes128_md5";
return self;
}
obfs * auth_aes128_sha1_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(auth_simple_local_data));
auth_simple_local_data_init((auth_simple_local_data*)self->l_data);
((auth_simple_local_data*)self->l_data)->hmac = ss_sha1_hmac_with_key;
((auth_simple_local_data*)self->l_data)->hash = ss_sha1_hash_func;
((auth_simple_local_data*)self->l_data)->hash_len = 20;
((auth_simple_local_data*)self->l_data)->salt = "auth_aes128_sha1";
return self;
}
void auth_simple_dispose(obfs *self) {
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
if (local->recv_buffer != NULL) {
free(local->recv_buffer);
local->recv_buffer = NULL;
}
if (local->user_key != NULL) {
free(local->user_key);
local->user_key = NULL;
}
free(local);
self->l_data = NULL;
dispose_obfs(self);
}
int auth_simple_pack_data(char *data, int datalength, char *outdata) {
unsigned char rand_len = (xorshift128plus() & 0xF) + 1;
int out_size = rand_len + datalength + 6;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
outdata[2] = rand_len;
memmove(outdata + rand_len + 2, data, datalength);
fillcrc32((unsigned char *)outdata, out_size);
return out_size;
}
void memintcopy_lt(void *mem, uint32_t val) {
((uint8_t *)mem)[0] = val;
((uint8_t *)mem)[1] = val >> 8;
((uint8_t *)mem)[2] = val >> 16;
((uint8_t *)mem)[3] = val >> 24;
}
int auth_simple_pack_auth_data(auth_simple_global_data *global, char *data, int datalength, char *outdata) {
unsigned char rand_len = (xorshift128plus() & 0xF) + 1;
int out_size = rand_len + datalength + 6 + 12;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
outdata[2] = rand_len;
++global->connection_id;
if (global->connection_id > 0xFF000000) {
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
}
time_t t = time(NULL);
memintcopy_lt(outdata + rand_len + 2, t);
memmove(outdata + rand_len + 2 + 4, global->local_client_id, 4);
memintcopy_lt(outdata + rand_len + 2 + 8, global->connection_id);
memmove(outdata + rand_len + 2 + 12, data, datalength);
fillcrc32((unsigned char *)outdata, out_size);
return out_size;
}
int auth_simple_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 64);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
if (len > 0 && local->has_sent_header == 0) {
int head_size = get_head_size(plaindata, datalength, 30);
if (head_size > datalength)
head_size = datalength;
pack_len = auth_simple_pack_auth_data((auth_simple_global_data *)self->server.g_data, data, head_size, buffer);
buffer += pack_len;
data += head_size;
len -= head_size;
local->has_sent_header = 1;
}
while ( len > auth_simple_pack_unit_size ) {
pack_len = auth_simple_pack_data(data, auth_simple_pack_unit_size, buffer);
buffer += pack_len;
data += auth_simple_pack_unit_size;
len -= auth_simple_pack_unit_size;
}
if (len > 0) {
pack_len = auth_simple_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_simple_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
while (local->recv_buffer_size > 2) {
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
if (length > local->recv_buffer_size)
break;
int crc = crc32((unsigned char*)recv_buffer, length);
if (crc != -1) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
int data_size = length - recv_buffer[2] - 6;
memmove(buffer, recv_buffer + 2 + recv_buffer[2], data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_sha1_pack_data(char *data, int datalength, char *outdata) {
unsigned char rand_len = (xorshift128plus() & 0xF) + 1;
int out_size = rand_len + datalength + 6;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
outdata[2] = rand_len;
memmove(outdata + rand_len + 2, data, datalength);
filladler32((unsigned char *)outdata, out_size);
return out_size;
}
int auth_sha1_pack_auth_data(auth_simple_global_data *global, server_info *server, char *data, int datalength, char *outdata) {
unsigned char rand_len = (xorshift128plus() & 0x7F) + 1;
int data_offset = rand_len + 4 + 2;
int out_size = data_offset + datalength + 12 + OBFS_HMAC_SHA1_LEN;
fillcrc32to((unsigned char *)server->key, server->key_len, (unsigned char *)outdata);
outdata[4] = out_size >> 8;
outdata[5] = out_size;
outdata[6] = rand_len;
++global->connection_id;
if (global->connection_id > 0xFF000000) {
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
}
time_t t = time(NULL);
memintcopy_lt(outdata + data_offset, t);
memmove(outdata + data_offset + 4, global->local_client_id, 4);
memintcopy_lt(outdata + data_offset + 8, global->connection_id);
memmove(outdata + data_offset + 12, data, datalength);
char hash[ONETIMEAUTH_BYTES * 2];
ss_sha1_hmac(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, server->iv);
memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN);
return out_size;
}
int auth_sha1_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 256);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
if (len > 0 && local->has_sent_header == 0) {
int head_size = get_head_size(plaindata, datalength, 30);
if (head_size > datalength)
head_size = datalength;
pack_len = auth_sha1_pack_auth_data((auth_simple_global_data *)self->server.g_data, &self->server, data, head_size, buffer);
buffer += pack_len;
data += head_size;
len -= head_size;
local->has_sent_header = 1;
}
while ( len > auth_simple_pack_unit_size ) {
pack_len = auth_sha1_pack_data(data, auth_simple_pack_unit_size, buffer);
buffer += pack_len;
data += auth_simple_pack_unit_size;
len -= auth_simple_pack_unit_size;
}
if (len > 0) {
pack_len = auth_sha1_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_sha1_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
while (local->recv_buffer_size > 2) {
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
if (length > local->recv_buffer_size)
break;
if (checkadler32((unsigned char*)recv_buffer, length) == 0) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
int pos = recv_buffer[2] + 2;
int data_size = length - pos - 4;
memmove(buffer, recv_buffer + pos, data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_sha1_v2_pack_data(char *data, int datalength, char *outdata) {
unsigned int rand_len = (datalength > 1300 ? 0 : datalength > 400 ? (xorshift128plus() & 0x7F) : (xorshift128plus() & 0x3FF)) + 1;
int out_size = rand_len + datalength + 6;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
if (rand_len < 128)
{
outdata[2] = rand_len;
}
else
{
outdata[2] = 0xFF;
outdata[3] = rand_len >> 8;
outdata[4] = rand_len;
}
memmove(outdata + rand_len + 2, data, datalength);
filladler32((unsigned char *)outdata, out_size);
return out_size;
}
int auth_sha1_v2_pack_auth_data(auth_simple_global_data *global, server_info *server, char *data, int datalength, char *outdata) {
unsigned int rand_len = (datalength > 1300 ? 0 : datalength > 400 ? (xorshift128plus() & 0x7F) : (xorshift128plus() & 0x3FF)) + 1;
int data_offset = rand_len + 4 + 2;
int out_size = data_offset + datalength + 12 + OBFS_HMAC_SHA1_LEN;
const char* salt = "auth_sha1_v2";
int salt_len = strlen(salt);
unsigned char *crc_salt = (unsigned char*)malloc(salt_len + server->key_len);
memcpy(crc_salt, salt, salt_len);
memcpy(crc_salt + salt_len, server->key, server->key_len);
fillcrc32to(crc_salt, salt_len + server->key_len, (unsigned char *)outdata);
free(crc_salt);
outdata[4] = out_size >> 8;
outdata[5] = out_size;
if (rand_len < 128)
{
outdata[6] = rand_len;
}
else
{
outdata[6] = 0xFF;
outdata[7] = rand_len >> 8;
outdata[8] = rand_len;
}
++global->connection_id;
if (global->connection_id > 0xFF000000) {
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
}
memmove(outdata + data_offset, global->local_client_id, 8);
memintcopy_lt(outdata + data_offset + 8, global->connection_id);
memmove(outdata + data_offset + 12, data, datalength);
char hash[ONETIMEAUTH_BYTES * 2];
ss_sha1_hmac(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, server->iv);
memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN);
return out_size;
}
int auth_sha1_v2_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 4096);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
if (len > 0 && local->has_sent_header == 0) {
int head_size = get_head_size(plaindata, datalength, 30);
if (head_size > datalength)
head_size = datalength;
pack_len = auth_sha1_v2_pack_auth_data((auth_simple_global_data *)self->server.g_data, &self->server, data, head_size, buffer);
buffer += pack_len;
data += head_size;
len -= head_size;
local->has_sent_header = 1;
}
while ( len > auth_simple_pack_unit_size ) {
pack_len = auth_sha1_v2_pack_data(data, auth_simple_pack_unit_size, buffer);
buffer += pack_len;
data += auth_simple_pack_unit_size;
len -= auth_simple_pack_unit_size;
}
if (len > 0) {
pack_len = auth_sha1_v2_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_sha1_v2_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
char error = 0;
while (local->recv_buffer_size > 2) {
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
local->recv_buffer_size = 0;
error = 1;
break;
}
if (length > local->recv_buffer_size)
break;
if (checkadler32((unsigned char*)recv_buffer, length) == 0) {
local->recv_buffer_size = 0;
error = 1;
break;
}
int pos = recv_buffer[2];
if (pos < 255)
{
pos += 2;
}
else
{
pos = ((recv_buffer[3] << 8) | recv_buffer[4]) + 2;
}
int data_size = length - pos - 4;
memmove(buffer, recv_buffer + pos, data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len;
if (error == 0) {
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
} else {
len = -1;
}
free(out_buffer);
return len;
}
int auth_sha1_v4_pack_data(char *data, int datalength, char *outdata) {
unsigned int rand_len = (datalength > 1300 ? 0 : datalength > 400 ? (xorshift128plus() & 0x7F) : (xorshift128plus() & 0x3FF)) + 1;
int out_size = rand_len + datalength + 8;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
uint32_t crc_val = crc32((unsigned char*)outdata, 2);
outdata[2] = crc_val;
outdata[3] = crc_val >> 8;
if (rand_len < 128)
{
outdata[4] = rand_len;
}
else
{
outdata[4] = 0xFF;
outdata[5] = rand_len >> 8;
outdata[6] = rand_len;
}
memmove(outdata + rand_len + 4, data, datalength);
filladler32((unsigned char *)outdata, out_size);
return out_size;
}
int auth_sha1_v4_pack_auth_data(auth_simple_global_data *global, server_info *server, char *data, int datalength, char *outdata) {
unsigned int rand_len = (datalength > 1300 ? 0 : datalength > 400 ? (xorshift128plus() & 0x7F) : (xorshift128plus() & 0x3FF)) + 1;
int data_offset = rand_len + 4 + 2;
int out_size = data_offset + datalength + 12 + OBFS_HMAC_SHA1_LEN;
const char* salt = "auth_sha1_v4";
int salt_len = strlen(salt);
unsigned char *crc_salt = (unsigned char*)malloc(salt_len + server->key_len + 2);
crc_salt[0] = outdata[0] = out_size >> 8;
crc_salt[1] = outdata[1] = out_size;
memcpy(crc_salt + 2, salt, salt_len);
memcpy(crc_salt + salt_len + 2, server->key, server->key_len);
fillcrc32to(crc_salt, salt_len + server->key_len + 2, (unsigned char *)outdata + 2);
free(crc_salt);
if (rand_len < 128)
{
outdata[6] = rand_len;
}
else
{
outdata[6] = 0xFF;
outdata[7] = rand_len >> 8;
outdata[8] = rand_len;
}
++global->connection_id;
if (global->connection_id > 0xFF000000) {
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
}
time_t t = time(NULL);
memintcopy_lt(outdata + data_offset, t);
memmove(outdata + data_offset + 4, global->local_client_id, 4);
memintcopy_lt(outdata + data_offset + 8, global->connection_id);
memmove(outdata + data_offset + 12, data, datalength);
char hash[ONETIMEAUTH_BYTES * 2];
ss_sha1_hmac(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, server->iv);
memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN);
return out_size;
}
int auth_sha1_v4_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 4096);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
if (len > 0 && local->has_sent_header == 0) {
int head_size = get_head_size(plaindata, datalength, 30);
if (head_size > datalength)
head_size = datalength;
pack_len = auth_sha1_v4_pack_auth_data((auth_simple_global_data *)self->server.g_data, &self->server, data, head_size, buffer);
buffer += pack_len;
data += head_size;
len -= head_size;
local->has_sent_header = 1;
}
while ( len > auth_simple_pack_unit_size ) {
pack_len = auth_sha1_v4_pack_data(data, auth_simple_pack_unit_size, buffer);
buffer += pack_len;
data += auth_simple_pack_unit_size;
len -= auth_simple_pack_unit_size;
}
if (len > 0) {
pack_len = auth_sha1_v4_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_sha1_v4_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
char error = 0;
while (local->recv_buffer_size > 4) {
uint32_t crc_val = crc32((unsigned char*)recv_buffer, 2);
if ((((uint32_t)recv_buffer[3] << 8) | recv_buffer[2]) != (crc_val & 0xffff)) {
local->recv_buffer_size = 0;
error = 1;
break;
}
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
local->recv_buffer_size = 0;
error = 1;
break;
}
if (length > local->recv_buffer_size)
break;
if (checkadler32((unsigned char*)recv_buffer, length) == 0) {
local->recv_buffer_size = 0;
error = 1;
break;
}
int pos = recv_buffer[4];
if (pos < 255)
{
pos += 4;
}
else
{
pos = (((int)recv_buffer[5] << 8) | recv_buffer[6]) + 4;
}
int data_size = length - pos - 4;
memmove(buffer, recv_buffer + pos, data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len;
if (error == 0) {
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
} else {
len = -1;
}
free(out_buffer);
return len;
}
int auth_aes128_sha1_pack_data(char *data, int datalength, char *outdata, auth_simple_local_data *local, server_info *server) {
unsigned int rand_len = (datalength > 1200 ? 0 : local->pack_id > 4 ? (xorshift128plus() & 0x20) : datalength > 900 ? (xorshift128plus() & 0x80) : (xorshift128plus() & 0x200)) + 1;
int out_size = rand_len + datalength + 8;
memcpy(outdata + rand_len + 4, data, datalength);
outdata[0] = out_size;
outdata[1] = out_size >> 8;
uint8_t key_len = local->user_key_len + 4;
uint8_t *key = (uint8_t*)malloc(key_len);
memcpy(key, local->user_key, local->user_key_len);
memintcopy_lt(key + key_len - 4, local->pack_id);
{
uint8_t rnd_data[rand_len];
rand_bytes(rnd_data, rand_len);
memcpy(outdata + 4, rnd_data, rand_len);
}
{
char hash[20];
local->hmac(hash, outdata, 2, key, key_len);
memcpy(outdata + 2, hash, 2);
}
if (rand_len < 128)
{
outdata[4] = rand_len;
}
else
{
outdata[4] = 0xFF;
outdata[5] = rand_len;
outdata[6] = rand_len >> 8;
}
++local->pack_id;
{
char hash[20];
local->hmac(hash, outdata, out_size - 4, key, key_len);
memcpy(outdata + out_size - 4, hash, 4);
}
free(key);
return out_size;
}
int auth_aes128_sha1_pack_auth_data(auth_simple_global_data *global, server_info *server, auth_simple_local_data *local, char *data, int datalength, char *outdata) {
unsigned int rand_len = (datalength > 400 ? (xorshift128plus() & 0x200) : (xorshift128plus() & 0x400));
int data_offset = rand_len + 16 + 4 + 4 + 7;
int out_size = data_offset + datalength + 4;
char encrypt[24];
char encrypt_data[16];
uint8_t *key = (uint8_t*)malloc(server->iv_len + server->key_len);
uint8_t key_len = server->iv_len + server->key_len;
memcpy(key, server->iv, server->iv_len);
memcpy(key + server->iv_len, server->key, server->key_len);
{
uint8_t rnd_data[rand_len];
rand_bytes(rnd_data, rand_len);
memcpy(outdata + data_offset - rand_len, rnd_data, rand_len);
}
++global->connection_id;
if (global->connection_id > 0xFF000000) {
rand_bytes(global->local_client_id, 8);
rand_bytes((uint8_t*)&global->connection_id, 4);
global->connection_id &= 0xFFFFFF;
}
time_t t = time(NULL);
memintcopy_lt(encrypt, t);
memcpy(encrypt + 4, global->local_client_id, 4);
memintcopy_lt(encrypt + 8, global->connection_id);
encrypt[12] = out_size;
encrypt[13] = out_size >> 8;
encrypt[14] = rand_len;
encrypt[15] = rand_len >> 8;
{
if (local->user_key == NULL) {
if(server->param != NULL && server->param[0] != 0) {
char *param = server->param;
char *delim = strchr(param, ':');
if(delim != NULL) {
char uid_str[16] = {};
strncpy(uid_str, param, delim - param);
char key_str[128];
strcpy(key_str, delim + 1);
long uid_long = strtol(uid_str, NULL, 10);
memintcopy_lt(local->uid, uid_long);
char hash[21] = {0};
local->hash(hash, key_str, strlen(key_str));
local->user_key_len = local->hash_len;
local->user_key = (uint8_t*)malloc(local->user_key_len);
memcpy(local->user_key, hash, local->hash_len);
}
}
if (local->user_key == NULL) {
rand_bytes((uint8_t *)local->uid, 4);
local->user_key_len = server->key_len;
local->user_key = (uint8_t*)malloc(local->user_key_len);
memcpy(local->user_key, server->key, local->user_key_len);
}
}
char encrypt_key_base64[256] = {0};
unsigned char encrypt_key[local->user_key_len];
memcpy(encrypt_key, local->user_key, local->user_key_len);
base64_encode(encrypt_key, local->user_key_len, encrypt_key_base64);
int base64_len;
base64_len = (local->user_key_len + 2) / 3 * 4;
memcpy(encrypt_key_base64 + base64_len, local->salt, strlen(local->salt));
char enc_key[16];
int enc_key_len = base64_len + strlen(local->salt);
bytes_to_key_with_size(encrypt_key_base64, enc_key_len, (uint8_t*)enc_key, 16);
ss_aes_128_cbc(encrypt, encrypt_data, enc_key);
memcpy(encrypt + 4, encrypt_data, 16);
memcpy(encrypt, local->uid, 4);
}
{
char hash[20];
local->hmac(hash, encrypt, 20, key, key_len);
memcpy(encrypt + 20, hash, 4);
}
{
uint8_t rnd[1];
rand_bytes(rnd, 1);
memcpy(outdata, rnd, 1);
char hash[20];
local->hmac(hash, (char *)rnd, 1, key, key_len);
memcpy(outdata + 1, hash, 6);
}
memcpy(outdata + 7, encrypt, 24);
memcpy(outdata + data_offset, data, datalength);
{
char hash[20];
local->hmac(hash, outdata, out_size - 4, local->user_key, local->user_key_len);
memmove(outdata + out_size - 4, hash, 4);
}
free(key);
return out_size;
}
int auth_aes128_sha1_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 4096);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
if (len > 0 && local->has_sent_header == 0) {
int head_size = 1200;
if (head_size > datalength)
head_size = datalength;
pack_len = auth_aes128_sha1_pack_auth_data((auth_simple_global_data *)self->server.g_data, &self->server, local, data, head_size, buffer);
buffer += pack_len;
data += head_size;
len -= head_size;
local->has_sent_header = 1;
}
while ( len > auth_simple_pack_unit_size ) {
pack_len = auth_aes128_sha1_pack_data(data, auth_simple_pack_unit_size, buffer, local, &self->server);
buffer += pack_len;
data += auth_simple_pack_unit_size;
len -= auth_simple_pack_unit_size;
}
if (len > 0) {
pack_len = auth_aes128_sha1_pack_data(data, len, buffer, local, &self->server);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int auth_aes128_sha1_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
//server_info *server = (server_info*)&self->server;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
int key_len = local->user_key_len + 4;
uint8_t *key = (uint8_t*)malloc(key_len);
memcpy(key, local->user_key, local->user_key_len);
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
char error = 0;
while (local->recv_buffer_size > 4) {
memintcopy_lt(key + key_len - 4, local->recv_id);
{
char hash[20];
local->hmac(hash, (char*)recv_buffer, 2, key, key_len);
if (memcmp(hash, recv_buffer + 2, 2)) {
local->recv_buffer_size = 0;
error = 1;
break;
}
}
int length = ((int)recv_buffer[1] << 8) + recv_buffer[0];
if (length >= 8192 || length < 8) {
local->recv_buffer_size = 0;
error = 1;
break;
}
if (length > local->recv_buffer_size)
break;
{
char hash[20];
local->hmac(hash, (char *)recv_buffer, length - 4, key, key_len);
if (memcmp(hash, recv_buffer + length - 4, 4))
{
local->recv_buffer_size = 0;
error = 1;
break;
}
}
++local->recv_id;
int pos = recv_buffer[4];
if (pos < 255)
{
pos += 4;
}
else
{
pos = (((int)recv_buffer[6] << 8) | recv_buffer[5]) + 4;
}
int data_size = length - pos - 4;
memmove(buffer, recv_buffer + pos, data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len;
if (error == 0) {
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
} else {
len = -1;
}
free(out_buffer);
free(key);
return len;
}
int auth_aes128_sha1_client_udp_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength + 8);
if (local->user_key == NULL) {
if(self->server.param != NULL && self->server.param[0] != 0) {
char *param = self->server.param;
char *delim = strchr(param, ':');
if(delim != NULL) {
char uid_str[16] = {};
strncpy(uid_str, param, delim - param);
char key_str[128];
strcpy(key_str, delim + 1);
long uid_long = strtol(uid_str, NULL, 10);
memintcopy_lt(local->uid, uid_long);
char hash[21] = {0};
local->hash(hash, key_str, strlen(key_str));
local->user_key_len = local->hash_len;
local->user_key = (uint8_t*)malloc(local->user_key_len);
memcpy(local->user_key, hash, local->hash_len);
}
}
if (local->user_key == NULL) {
rand_bytes((uint8_t *)local->uid, 4);
local->user_key_len = self->server.key_len;
local->user_key = (uint8_t*)malloc(local->user_key_len);
memcpy(local->user_key, self->server.key, local->user_key_len);
}
}
int outlength = datalength + 8;
memmove(out_buffer, plaindata, datalength);
memmove(out_buffer + datalength, local->uid, 4);
{
char hash[20];
local->hmac(hash, out_buffer, outlength - 4, local->user_key, local->user_key_len);
memmove(out_buffer + outlength - 4, hash, 4);
}
if (*capacity < outlength) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = outlength * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, outlength);
free(out_buffer);
return outlength;
}
int auth_aes128_sha1_client_udp_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity) {
if (datalength <= 4)
return 0;
char *plaindata = *pplaindata;
auth_simple_local_data *local = (auth_simple_local_data*)self->l_data;
char hash[20];
local->hmac(hash, plaindata, datalength - 4, self->server.key, self->server.key_len);
if (memcmp(hash, plaindata + datalength - 4, 4))
{
return 0;
}
return datalength - 4;
}

View File

@ -0,0 +1,30 @@
/*
* auth.h - Define shadowsocksR server's buffers and callbacks
*
* Copyright (C) 2015 - 2016, Break Wa11 <mmgac001@gmail.com>
*/
#ifndef _AUTH_H
#define _AUTH_H
void * auth_simple_init_data();
obfs * auth_simple_new_obfs();
void auth_simple_dispose(obfs *self);
int auth_simple_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_simple_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_v2_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_v2_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_v4_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_sha1_v4_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_aes128_sha1_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int auth_aes128_sha1_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
#endif // _AUTH_H

View File

@ -0,0 +1,119 @@
#include "base64.h"
/* BASE 64 encode table */
static const char base64en[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define BASE64_PAD '='
#define BASE64DE_FIRST '+'
#define BASE64DE_LAST 'z'
/* ASCII order for BASE 64 decode, -1 in unused character */
static const signed char base64de[] = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
/* '+', ',', '-', '.', '/', */
-1, -1, -1, 62, -1, -1, -1, 63,
/* '0', '1', '2', '3', '4', '5', '6', '7', */
52, 53, 54, 55, 56, 57, 58, 59,
/* '8', '9', ':', ';', '<', '=', '>', '?', */
60, 61, -1, -1, -1, -1, -1, -1,
/* '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */
-1, 0, 1, 2, 3, 4, 5, 6,
/* 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */
7, 8, 9, 10, 11, 12, 13, 14,
/* 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */
15, 16, 17, 18, 19, 20, 21, 22,
/* 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */
23, 24, 25, -1, -1, -1, -1, -1,
/* '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */
-1, 26, 27, 28, 29, 30, 31, 32,
/* 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */
33, 34, 35, 36, 37, 38, 39, 40,
/* 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */
41, 42, 43, 44, 45, 46, 47, 48,
/* 'x', 'y', 'z', */
49, 50, 51,
};
int
base64_encode(const unsigned char *in, unsigned int inlen, char *out)
{
unsigned int i, j;
for (i = j = 0; i < inlen; i++) {
int s = i % 3; /* from 6/gcd(6, 8) */
switch (s) {
case 0:
out[j++] = base64en[(in[i] >> 2) & 0x3F];
continue;
case 1:
out[j++] = base64en[((in[i-1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)];
continue;
case 2:
out[j++] = base64en[((in[i-1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)];
out[j++] = base64en[in[i] & 0x3F];
}
}
/* move back */
i -= 1;
/* check the last and add padding */
if ((i % 3) == 0) {
out[j++] = base64en[(in[i] & 0x3) << 4];
out[j++] = BASE64_PAD;
out[j++] = BASE64_PAD;
} else if ((i % 3) == 1) {
out[j++] = base64en[(in[i] & 0xF) << 2];
out[j++] = BASE64_PAD;
}
return BASE64_OK;
}
int
base64_decode(const char *in, unsigned int inlen, unsigned char *out)
{
unsigned int i, j;
for (i = j = 0; i < inlen; i++) {
int c;
int s = i % 4; /* from 8/gcd(6, 8) */
if (in[i] == '=')
return BASE64_OK;
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST ||
(c = base64de[(int)in[i]]) == -1)
return BASE64_INVALID;
switch (s) {
case 0:
out[j] = ((unsigned int)c << 2) & 0xFF;
continue;
case 1:
out[j++] += ((unsigned int)c >> 4) & 0x3;
/* if not last char with padding */
if (i < (inlen - 3) || in[inlen - 2] != '=')
out[j] = ((unsigned int)c & 0xF) << 4;
continue;
case 2:
out[j++] += ((unsigned int)c >> 2) & 0xF;
/* if not last char with padding */
if (i < (inlen - 2) || in[inlen - 1] != '=')
out[j] = ((unsigned int)c & 0x3) << 6;
continue;
case 3:
out[j++] += (unsigned char)c;
}
}
return BASE64_OK;
}

View File

@ -0,0 +1,16 @@
#ifndef __BASE64_H__
#define __BASE64_H__
enum {BASE64_OK = 0, BASE64_INVALID};
#define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4)
#define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3)
int
base64_encode(const unsigned char *in, unsigned int inlen, char *out);
int
base64_decode(const char *in, unsigned int inlen, unsigned char *out);
#endif /* __BASE64_H__ */

View File

@ -0,0 +1,308 @@
/*
* cache.c - Manage the connection cache for UDPRELAY
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/*
* Original Author: Oliver Lorenz (ol), olli@olorenz.org, https://olorenz.org
* License: This is licensed under the same terms as uthash itself
*/
#include <errno.h>
#include <stdlib.h>
#include "cache.h"
#include "utils.h"
#ifdef __MINGW32__
#include "win32.h"
#endif
/** Creates a new cache object
*
* @param dst
* Where the newly allocated cache object will be stored in
*
* @param capacity
* The maximum number of elements this cache object can hold
*
* @return EINVAL if dst is NULL, ENOMEM if malloc fails, 0 otherwise
*/
int
cache_create(struct cache **dst, const size_t capacity,
void (*free_cb)(void *key, void *element))
{
struct cache *new = NULL;
if (!dst) {
return EINVAL;
}
if ((new = malloc(sizeof(*new))) == NULL) {
return ENOMEM;
}
new->max_entries = capacity;
new->entries = NULL;
new->free_cb = free_cb;
*dst = new;
return 0;
}
/** Frees an allocated cache object
*
* @param cache
* The cache object to free
*
* @param keep_data
* Whether to free contained data or just delete references to it
*
* @return EINVAL if cache is NULL, 0 otherwise
*/
int
cache_delete(struct cache *cache, int keep_data)
{
struct cache_entry *entry, *tmp;
if (!cache) {
return EINVAL;
}
if (keep_data) {
HASH_CLEAR(hh, cache->entries);
} else {
HASH_ITER(hh, cache->entries, entry, tmp){
HASH_DEL(cache->entries, entry);
if (entry->data != NULL) {
if (cache->free_cb) {
cache->free_cb(entry->key, entry->data);
} else {
ss_free(entry->data);
}
}
ss_free(entry->key);
ss_free(entry);
}
}
ss_free(cache);
return 0;
}
/** Clear old cache object
*
* @param cache
* The cache object to clear
*
* @param age
* Clear only objects older than the age (sec)
*
* @return EINVAL if cache is NULL, 0 otherwise
*/
int
cache_clear(struct cache *cache, ev_tstamp age)
{
struct cache_entry *entry, *tmp;
if (!cache) {
return EINVAL;
}
ev_tstamp now = ev_time();
HASH_ITER(hh, cache->entries, entry, tmp){
if (now - entry->ts > age) {
HASH_DEL(cache->entries, entry);
if (entry->data != NULL) {
if (cache->free_cb) {
cache->free_cb(entry->key, entry->data);
} else {
ss_free(entry->data);
}
}
ss_free(entry->key);
ss_free(entry);
}
}
return 0;
}
/** Removes a cache entry
*
* @param cache
* The cache object
*
* @param key
* The key of the entry to remove
*
* @param key_len
* The length of key
*
* @return EINVAL if cache is NULL, 0 otherwise
*/
int
cache_remove(struct cache *cache, char *key, size_t key_len)
{
struct cache_entry *tmp;
if (!cache || !key) {
return EINVAL;
}
HASH_FIND(hh, cache->entries, key, key_len, tmp);
if (tmp) {
HASH_DEL(cache->entries, tmp);
if (tmp->data != NULL) {
if (cache->free_cb) {
cache->free_cb(tmp->key, tmp->data);
} else {
ss_free(tmp->data);
}
}
ss_free(tmp->key);
ss_free(tmp);
}
return 0;
}
/** Checks if a given key is in the cache
*
* @param cache
* The cache object
*
* @param key
* The key to look-up
*
* @param key_len
* The length of key
*
* @param result
* Where to store the result if key is found.
*
* A warning: Even though result is just a pointer,
* you have to call this function with a **ptr,
* otherwise this will blow up in your face.
*
* @return EINVAL if cache is NULL, 0 otherwise
*/
int
cache_lookup(struct cache *cache, char *key, size_t key_len, void *result)
{
struct cache_entry *tmp = NULL;
char **dirty_hack = result;
if (!cache || !key || !result) {
return EINVAL;
}
HASH_FIND(hh, cache->entries, key, key_len, tmp);
if (tmp) {
HASH_DELETE(hh, cache->entries, tmp);
tmp->ts = ev_time();
HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp);
*dirty_hack = tmp->data;
} else {
*dirty_hack = result = NULL;
}
return 0;
}
int
cache_key_exist(struct cache *cache, char *key, size_t key_len)
{
struct cache_entry *tmp = NULL;
if (!cache || !key) {
return 0;
}
HASH_FIND(hh, cache->entries, key, key_len, tmp);
if (tmp) {
HASH_DELETE(hh, cache->entries, tmp);
tmp->ts = ev_time();
HASH_ADD_KEYPTR(hh, cache->entries, tmp->key, key_len, tmp);
return 1;
} else {
return 0;
}
return 0;
}
/** Inserts a given <key, value> pair into the cache
*
* @param cache
* The cache object
*
* @param key
* The key that identifies <value>
*
* @param key_len
* The length of key
*
* @param data
* Data associated with <key>
*
* @return EINVAL if cache is NULL, ENOMEM if malloc fails, 0 otherwise
*/
int
cache_insert(struct cache *cache, char *key, size_t key_len, void *data)
{
struct cache_entry *entry = NULL;
struct cache_entry *tmp_entry = NULL;
if (!cache) {
return EINVAL;
}
if ((entry = malloc(sizeof(*entry))) == NULL) {
return ENOMEM;
}
entry->key = ss_malloc(key_len + 1);
memcpy(entry->key, key, key_len);
entry->key[key_len] = 0;
entry->data = data;
entry->ts = ev_time();
HASH_ADD_KEYPTR(hh, cache->entries, entry->key, key_len, entry);
if (HASH_COUNT(cache->entries) >= cache->max_entries) {
HASH_ITER(hh, cache->entries, entry, tmp_entry){
HASH_DELETE(hh, cache->entries, entry);
if (entry->data != NULL) {
if (cache->free_cb) {
cache->free_cb(entry->key, entry->data);
} else {
ss_free(entry->data);
}
}
ss_free(entry->key);
ss_free(entry);
break;
}
}
return 0;
}

View File

@ -0,0 +1,62 @@
/*
* cache.h - Define the cache manager interface
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
/*
* Original Author: Oliver Lorenz (ol), olli@olorenz.org, https://olorenz.org
* License: This is licensed under the same terms as uthash itself
*/
#ifndef _CACHE_
#define _CACHE_
#include "uthash.h"
#include "ev.h"
/**
* A cache entry
*/
struct cache_entry {
char *key; /**<The key */
void *data; /**<Payload */
ev_tstamp ts; /**<Timestamp */
UT_hash_handle hh; /**<Hash Handle for uthash */
};
/**
* A cache object
*/
struct cache {
size_t max_entries; /**<Amount of entries this cache object can hold */
struct cache_entry *entries; /**<Head pointer for uthash */
void (*free_cb) (void *key, void *element); /**<Callback function to free cache entries */
};
int cache_create(struct cache **dst, const size_t capacity,
void (*free_cb)(void *key, void *element));
int cache_delete(struct cache *cache, int keep_data);
int cache_clear(struct cache *cache, ev_tstamp age);
int cache_lookup(struct cache *cache, char *key, size_t key_len, void *result);
int cache_insert(struct cache *cache, char *key, size_t key_len, void *data);
int cache_remove(struct cache *cache, char *key, size_t key_len);
int cache_key_exist(struct cache *cache, char *key, size_t key_len);
#endif

View File

@ -0,0 +1,236 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include<arpa/inet.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>
//#define __DEBUG__
#ifdef __DEBUG__
#define DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"/n", __LINE__, ##__VA_ARGS__)
#else
#define DEBUG(format,...)
#endif
static sigjmp_buf jmpbuf;
static void alarm_func()
{
siglongjmp(jmpbuf, 1);
}
static struct hostent *timeGethostbyname(const char *domain, int timeout)
{
struct hostent *ipHostent = NULL;
signal(SIGALRM, alarm_func);
if(sigsetjmp(jmpbuf, 1) != 0)
{
alarm(0);//timout
signal(SIGALRM, SIG_IGN);
return NULL;
}
alarm(timeout);//setting alarm
ipHostent = gethostbyname(domain);
signal(SIGALRM, SIG_IGN);
return ipHostent;
}
#define MY_HTTP_DEFAULT_PORT 80
#define BUFFER_SIZE 1024
#define HTTP_POST "POST /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n"\
"Content-Type:application/x-www-form-urlencoded\r\nContent-Length: %d\r\n\r\n%s"
#define HTTP_GET "GET /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n"
static int http_parse_url(const char *url,char *host,char *file,int *port)
{
char *ptr1,*ptr2;
int len = 0;
if(!url || !host || !file || !port){
return 1;
}
ptr1 = (char *)url;
if(!strncmp(ptr1,"http://",strlen("http://"))){
ptr1 += strlen("http://");
}else{
return 1;
}
ptr2 = strchr(ptr1,'/');
if(ptr2){
len = strlen(ptr1) - strlen(ptr2);
memcpy(host,ptr1,len);
host[len] = '\0';
if(*(ptr2 + 1)){
memcpy(file,ptr2 + 1,strlen(ptr2) - 1 );
file[strlen(ptr2) - 1] = '\0';
}
}else{
memcpy(host,ptr1,strlen(ptr1));
host[strlen(ptr1)] = '\0';
}
//get host and ip
ptr1 = strchr(host,':');
if(ptr1){
*ptr1++ = '\0';
*port = atoi(ptr1);
}else{
*port = MY_HTTP_DEFAULT_PORT;
}
return 0;
}
static int http_tcpclient_recv(int socket,char *lpbuff){
int recvnum = 0;
recvnum = recv(socket, lpbuff,BUFFER_SIZE*4,0);
return recvnum;
}
static int http_tcpclient_send(int socket,char *buff,int size){
int sent=0,tmpres=0;
while(sent < size){
tmpres = send(socket,buff+sent,size-sent,0);
if(tmpres == -1){
return 1;
}
sent += tmpres;
}
return sent;
}
int http_get(const char *url,int socket_fd)
{
char lpbuf[BUFFER_SIZE*4] = {'\0'};
char host_addr[BUFFER_SIZE] = {'\0'};
char file[BUFFER_SIZE] = {'\0'};
int port = 0;
if(!url){
DEBUG(" failed!\n");
return 1;
}
if(http_parse_url(url,host_addr,file,&port)){
DEBUG("http_parse_url failed!\n");
return 1;
}
DEBUG("url: %s\thost_addr : %s\tfile:%s\t,%d\n",url,host_addr,file,port);
if(socket_fd < 0){
DEBUG("http_tcpclient_create failed\n");
return 1;
}
sprintf(lpbuf,HTTP_GET,file,host_addr,port);
if(http_tcpclient_send(socket_fd,lpbuf,strlen(lpbuf)) < 0){
DEBUG("http_tcpclient_send failed..\n");
return 1;
}
DEBUG("request:\n%s\n",lpbuf);
if(http_tcpclient_recv(socket_fd,lpbuf) <= 0){
DEBUG("http_tcpclient_recv failed\n");
close(socket_fd);
return 1;
}
DEBUG("rec:\n%s\n",lpbuf);
close(socket_fd);
//return http_parse_result(lpbuf);
return 0;
}
int main(int argc, char *argv[])
{
int fd,http_flag=0,http_ret=1;
struct sockaddr_in addr;
struct hostent *host;
struct timeval timeo = {3, 0};
socklen_t len = sizeof(timeo);
char http_url[100]="http://";
fd = socket(AF_INET, SOCK_STREAM, 0);
if (argc >= 4)
timeo.tv_sec = atoi(argv[3]);
if (argc>=5)
http_flag=1;
if((host=timeGethostbyname(argv[1],timeo.tv_sec)) == NULL) {
DEBUG("gethostbyname err\n");
return 1;
}
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len) == -1)
{
DEBUG("setsockopt send err\n");
return 1;
}
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, len) == -1)
{
DEBUG("setsockopt recv err\n");
return 1;
}
addr.sin_family = AF_INET;
addr.sin_addr = *((struct in_addr *)host->h_addr);
//addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
if (errno == EINPROGRESS)
{
DEBUG("timeout err\n");
return 1;
}
DEBUG("connect err\n");
return 1;
}
if(http_flag==0)
{
close(fd);
return 0;
}
strcat(http_url,argv[1]);
http_ret=http_get(http_url,fd);
if(http_ret==1)
{
DEBUG("recv err");
return 1;
}
else
{
DEBUG("recv ok");
return 0;
}
}

View File

@ -0,0 +1,58 @@
/*
* common.h - Provide global definitions
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _COMMON_H
#define _COMMON_H
#define DEFAULT_CONF_PATH "/etc/shadowsocks-libev/config.json"
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
#endif
#if defined(MODULE_TUNNEL) || defined(MODULE_REDIR)
#define MODULE_LOCAL
#endif
int init_udprelay(const char *server_host, const char *server_port,
#ifdef MODULE_LOCAL
const struct sockaddr *remote_addr, const int remote_addr_len,
#ifdef MODULE_TUNNEL
const ss_addr_t tunnel_addr,
#endif
#endif
int mtu, int method, int auth, int timeout, const char *iface, const char *protocol, const char *protocol_param);
void free_udprelay(void);
#ifdef ANDROID
int protect_socket(int fd);
int send_traffic_stat(uint64_t tx, uint64_t rx);
#endif
#define STAGE_ERROR -1 /* Error detected */
#define STAGE_INIT 0 /* Initial stage */
#define STAGE_HANDSHAKE 1 /* Handshake with client */
#define STAGE_PARSE 2 /* Parse the header */
#define STAGE_RESOLVE 4 /* Resolve the hostname */
#define STAGE_STREAM 5 /* Stream between client and server */
#endif // _COMMON_H

View File

@ -0,0 +1,97 @@
static uint32_t crc32_table[256] = {0};
void init_crc32_table(void) {
uint32_t c, i, j;
if (crc32_table[0] == 0) {
for (i = 0; i < 256; i++) {
c = i;
for (j = 0; j < 8; j++) {
if (c & 1)
c = 0xedb88320L ^ (c >> 1);
else
c = c >> 1;
}
crc32_table[i] = c;
}
}
}
uint32_t crc32(unsigned char *buffer, unsigned int size) {
uint32_t crc = 0xFFFFFFFF;
unsigned int i;
for (i = 0; i < size; i++) {
crc = crc32_table[(crc ^ buffer[i]) & 0xFF] ^ (crc >> 8);
}
return crc ^ 0xFFFFFFFF;
}
void fillcrc32to(unsigned char *buffer, unsigned int size, unsigned char *outbuffer) {
uint32_t crc = 0xFFFFFFFF;
unsigned int i;
for (i = 0; i < size; i++) {
crc = crc32_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
}
crc ^= 0xFFFFFFFF;
outbuffer[0] = crc;
outbuffer[1] = crc >> 8;
outbuffer[2] = crc >> 16;
outbuffer[3] = crc >> 24;
}
void fillcrc32(unsigned char *buffer, unsigned int size) {
uint32_t crc = 0xFFFFFFFF;
unsigned int i;
size -= 4;
for (i = 0; i < size; i++) {
crc = crc32_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
}
buffer += size;
buffer[0] = crc;
buffer[1] = crc >> 8;
buffer[2] = crc >> 16;
buffer[3] = crc >> 24;
}
void adler32_short(unsigned char *buffer, unsigned int size, uint32_t *a, uint32_t *b) {
for (int i = 0; i < size; i++) {
*a += buffer[i];
*b += *a;
}
*a %= 65521;
*b %= 65521;
}
#define NMAX 5552
uint32_t adler32(unsigned char *buffer, unsigned int size) {
uint32_t a = 1;
uint32_t b = 0;
while ( size >= NMAX ) {
adler32_short(buffer, NMAX, &a, &b);
buffer += NMAX;
size -= NMAX;
}
adler32_short(buffer, size, &a, &b);
return (b << 16) + a;
}
#undef NMAX
void filladler32(unsigned char *buffer, unsigned int size) {
size -= 4;
uint32_t checksum = adler32(buffer, size);
buffer += size;
buffer[0] = checksum;
buffer[1] = checksum >> 8;
buffer[2] = checksum >> 16;
buffer[3] = checksum >> 24;
}
int checkadler32(unsigned char *buffer, unsigned int size) {
size -= 4;
uint32_t checksum = adler32(buffer, size);
buffer += size;
return checksum == (((uint32_t)buffer[3] << 24)
| ((uint32_t)buffer[2] << 16)
| ((uint32_t)buffer[1] << 8)
| (uint32_t)buffer[0]);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,222 @@
/*
* encrypt.h - Define the enryptor's interface
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _ENCRYPT_H
#define _ENCRYPT_H
#ifndef __MINGW32__
#include <sys/socket.h>
#else
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#if defined(USE_CRYPTO_OPENSSL)
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
typedef EVP_CIPHER cipher_kt_t;
typedef EVP_CIPHER_CTX cipher_evp_t;
typedef EVP_MD digest_type_t;
#define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH
#define MAX_IV_LENGTH EVP_MAX_IV_LENGTH
#define MAX_MD_SIZE EVP_MAX_MD_SIZE
#elif defined(USE_CRYPTO_POLARSSL)
#include <polarssl/cipher.h>
#include <polarssl/md.h>
typedef cipher_info_t cipher_kt_t;
typedef cipher_context_t cipher_evp_t;
typedef md_info_t digest_type_t;
#define MAX_KEY_LENGTH 64
#define MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH
#define MAX_MD_SIZE POLARSSL_MD_MAX_SIZE
#elif defined(USE_CRYPTO_MBEDTLS)
#include <mbedtls/cipher.h>
#include <mbedtls/md.h>
typedef mbedtls_cipher_info_t cipher_kt_t;
typedef mbedtls_cipher_context_t cipher_evp_t;
typedef mbedtls_md_info_t digest_type_t;
#define MAX_KEY_LENGTH 64
#define MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH
#define MAX_MD_SIZE MBEDTLS_MD_MAX_SIZE
/* we must have MBEDTLS_CIPHER_MODE_CFB defined */
#if !defined(MBEDTLS_CIPHER_MODE_CFB)
#error Cipher Feedback mode a.k.a CFB not supported by your mbed TLS.
#endif
#endif
#ifdef USE_CRYPTO_APPLECC
#include <CommonCrypto/CommonCrypto.h>
#define kCCAlgorithmInvalid UINT32_MAX
#define kCCContextValid 0
#define kCCContextInvalid -1
typedef struct {
CCCryptorRef cryptor;
int valid;
CCOperation encrypt;
CCAlgorithm cipher;
CCMode mode;
CCPadding padding;
uint8_t iv[MAX_IV_LENGTH];
uint8_t key[MAX_KEY_LENGTH];
size_t iv_len;
size_t key_len;
} cipher_cc_t;
#endif
typedef struct {
cipher_evp_t *evp;
#ifdef USE_CRYPTO_APPLECC
cipher_cc_t cc;
#endif
uint8_t iv[MAX_IV_LENGTH];
} cipher_ctx_t;
typedef struct {
cipher_kt_t *info;
size_t iv_len;
size_t key_len;
} cipher_t;
#ifdef HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#define SODIUM_BLOCK_SIZE 64
enum crpher_index {
NONE = -1,
TABLE = 0,
RC4,
RC4_MD5_6,
RC4_MD5,
AES_128_CFB,
AES_192_CFB,
AES_256_CFB,
AES_128_CTR,
AES_192_CTR,
AES_256_CTR,
BF_CFB,
CAMELLIA_128_CFB,
CAMELLIA_192_CFB,
CAMELLIA_256_CFB,
CAST5_CFB,
DES_CFB,
IDEA_CFB,
RC2_CFB,
SEED_CFB,
SALSA20,
CHACHA20,
CHACHA20IETF,
CIPHER_NUM,
};
#define ONETIMEAUTH_FLAG 0x10
#define ADDRTYPE_MASK 0xEF
#define ONETIMEAUTH_BYTES 10U
#define MD5_BYTES 16U
#define SHA1_BYTES 20U
#define CLEN_BYTES 2U
#define AUTH_BYTES (ONETIMEAUTH_BYTES + CLEN_BYTES)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
typedef struct buffer {
size_t idx;
size_t len;
size_t capacity;
char *array;
} buffer_t;
typedef struct chunk {
uint32_t idx;
uint32_t len;
uint32_t counter;
buffer_t *buf;
} chunk_t;
typedef struct enc_ctx {
uint8_t init;
uint64_t counter;
cipher_ctx_t evp;
} enc_ctx_t;
void bytes_to_key_with_size(const char *pass, size_t len, uint8_t *md, size_t md_size);
int ss_encrypt_all(buffer_t *plaintext, int method, int auth, size_t capacity);
int ss_decrypt_all(buffer_t *ciphertext, int method, int auth, size_t capacity);
int ss_encrypt(buffer_t *plaintext, enc_ctx_t *ctx, size_t capacity);
int ss_decrypt(buffer_t *ciphertext, enc_ctx_t *ctx, size_t capacity);
void enc_ctx_init(int method, enc_ctx_t *ctx, int enc);
int enc_init(const char *pass, const char *method);
int enc_get_iv_len(void);
uint8_t* enc_get_key(void);
int enc_get_key_len(void);
void cipher_context_release(cipher_ctx_t *evp);
unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md);
int ss_md5_hmac(char *auth, char *msg, int msg_len, uint8_t *iv);
int ss_md5_hmac_with_key(char *auth, char *msg, int msg_len, uint8_t *auth_key, int key_len);
int ss_md5_hash_func(char *auth, char *msg, int msg_len);
int ss_sha1_hmac(char *auth, char *msg, int msg_len, uint8_t *iv);
int ss_sha1_hmac_with_key(char *auth, char *msg, int msg_len, uint8_t *auth_key, int key_len);
int ss_sha1_hash_func(char *auth, char *msg, int msg_len);
int ss_aes_128_cbc(char *encrypt, char *out_data, char *key);
int ss_onetimeauth(buffer_t *buf, uint8_t *iv, size_t capacity);
int ss_onetimeauth_verify(buffer_t *buf, uint8_t *iv);
int ss_check_hash(buffer_t *buf, chunk_t *chunk, enc_ctx_t *ctx, size_t capacity);
int ss_gen_hash(buffer_t *buf, uint32_t *counter, enc_ctx_t *ctx, size_t capacity);
int balloc(buffer_t *ptr, size_t capacity);
int brealloc(buffer_t *ptr, size_t len, size_t capacity);
void bfree(buffer_t *ptr);
#endif // _ENCRYPT_H

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h> /* malloc() */
#include <string.h> /* strncpy() */
#include <strings.h> /* strncasecmp() */
#include <ctype.h> /* isblank() */
#include "http.h"
#include "protocol.h"
#define SERVER_NAME_LEN 256
static int parse_http_header(const char *, size_t, char **);
static int get_header(const char *, const char *, int, char **);
static int next_header(const char **, int *);
static const protocol_t http_protocol_st = {
.default_port = 80,
.parse_packet = &parse_http_header,
};
const protocol_t *const http_protocol = &http_protocol_st;
/*
* Parses a HTTP request for the Host: header
*
* Returns:
* >=0 - length of the hostname and updates *hostname
* caller is responsible for freeing *hostname
* -1 - Incomplete request
* -2 - No Host header included in this request
* -3 - Invalid hostname pointer
* -4 - malloc failure
* < -4 - Invalid HTTP request
*
*/
static int
parse_http_header(const char *data, size_t data_len, char **hostname)
{
int result, i;
if (hostname == NULL)
return -3;
if (data_len == 0)
return -1;
result = get_header("Host:", data, data_len, hostname);
if (result < 0)
return result;
/*
* if the user specifies the port in the request, it is included here.
* Host: example.com:80
* so we trim off port portion
*/
for (i = result - 1; i >= 0; i--)
if ((*hostname)[i] == ':') {
(*hostname)[i] = '\0';
result = i;
break;
}
return result;
}
static int
get_header(const char *header, const char *data, int data_len, char **value)
{
int len, header_len;
header_len = strlen(header);
/* loop through headers stopping at first blank line */
while ((len = next_header(&data, &data_len)) != 0)
if (len > header_len && strncasecmp(header, data, header_len) == 0) {
/* Eat leading whitespace */
while (header_len < len && isblank(data[header_len]))
header_len++;
*value = malloc(len - header_len + 1);
if (*value == NULL)
return -4;
strncpy(*value, data + header_len, len - header_len);
(*value)[len - header_len] = '\0';
return len - header_len;
}
/* If there is no data left after reading all the headers then we do not
* have a complete HTTP request, there must be a blank line */
if (data_len == 0)
return -1;
return -2;
}
static int
next_header(const char **data, int *len)
{
int header_len;
/* perhaps we can optimize this to reuse the value of header_len, rather
* than scanning twice.
* Walk our data stream until the end of the header */
while (*len > 2 && (*data)[0] != '\r' && (*data)[1] != '\n') {
(*len)--;
(*data)++;
}
/* advanced past the <CR><LF> pair */
*data += 2;
*len -= 2;
/* Find the length of the next header */
header_len = 0;
while (*len > header_len + 1
&& (*data)[header_len] != '\r'
&& (*data)[header_len + 1] != '\n')
header_len++;
return header_len;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HTTP_H
#define HTTP_H
#include <stdio.h>
#include "protocol.h"
const protocol_t *const http_protocol;
#endif

View File

@ -0,0 +1,625 @@
#include "http_simple.h"
static char* g_useragent[] = {
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0",
"Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)",
"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
"Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36",
"Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
};
static int g_useragent_index = -1;
typedef struct http_simple_local_data {
int has_sent_header;
int has_recv_header;
char *encode_buffer;
int host_matched;
char *recv_buffer;
int recv_buffer_size;
}http_simple_local_data;
void http_simple_local_data_init(http_simple_local_data* local) {
local->has_sent_header = 0;
local->has_recv_header = 0;
local->encode_buffer = NULL;
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->host_matched = 0;
if (g_useragent_index == -1) {
g_useragent_index = xorshift128plus() % (sizeof(g_useragent) / sizeof(*g_useragent));
}
}
obfs * http_simple_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(http_simple_local_data));
http_simple_local_data_init((http_simple_local_data*)self->l_data);
return self;
}
void http_simple_dispose(obfs *self) {
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
free(local);
dispose_obfs(self);
}
char http_simple_hex(char c) {
if (c < 10) return c + '0';
return c - 10 + 'a';
}
int get_data_from_http_header(char *data, char **outdata) {
char *delim = "\r\n";
char *delim_hex = "%";
int outlength = 0;
char *buf = *outdata;
char *p_line;
p_line = strtok(data, delim);
//while(p_line)
{
char *p_hex;
p_hex = strtok(p_line, delim_hex);
while((p_hex = strtok(NULL, delim_hex)))
{
char hex = 0;
if(strlen(p_hex) <= 0)
{
continue;
}
if(strlen(p_hex) > 2)
{
char *c_hex = (char*)malloc(2);
memcpy(c_hex, p_hex, 2);
hex = (char)strtol(c_hex, NULL, 16);
free(c_hex);
}
else
{
hex = (char)strtol(p_hex, NULL, 16);
}
outlength += 1;
buf = (char*)realloc(buf, outlength);
buf[outlength - 1] = hex;
}
//p_line = strtok(p_line, delim);
}
return outlength;
}
void get_host_from_http_header(char *data, char **host) {
char* data_begin = strstr(data, "Host: ");
if(data_begin == NULL)
{
return;
}
data_begin += 6;
char* data_end = strstr(data_begin, "\r\n");
char* data_end_port = strstr(data_begin, ":");
int host_length = 0;
if(data_end_port != NULL)
{
host_length = data_end_port - data_begin;
}
else
{
host_length = data_end - data_begin;
}
if(host_length <= 0)
{
return;
}
memset(*host, 0x00, 1024);
memcpy(*host, data_begin, host_length);
}
void http_simple_encode_head(http_simple_local_data *local, char *data, int datalength) {
if (local->encode_buffer == NULL) {
local->encode_buffer = (char*)malloc(datalength * 3 + 1);
}
int pos = 0;
for (; pos < datalength; ++pos) {
local->encode_buffer[pos * 3] = '%';
local->encode_buffer[pos * 3 + 1] = http_simple_hex(((unsigned char)data[pos] >> 4));
local->encode_buffer[pos * 3 + 2] = http_simple_hex(data[pos] & 0xF);
}
local->encode_buffer[pos * 3] = 0;
}
int http_simple_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos;
char hostport[128];
int head_size = self->server.head_len + (xorshift128plus() & 0x3F);
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
char * body_buffer = NULL;
if (head_size > datalength)
head_size = datalength;
http_simple_encode_head(local, encryptdata, head_size);
if (self->server.param && strlen(self->server.param) == 0)
self->server.param = NULL;
strncpy(hosts, self->server.param ? self->server.param : self->server.host, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
host_num = xorshift128plus() % host_num;
if (self->server.port == 80)
sprintf(hostport, "%s", phost[host_num]);
else
sprintf(hostport, "%s:%d", phost[host_num], self->server.port);
if (body_buffer) {
sprintf(out_buffer,
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"%s\r\n\r\n",
local->encode_buffer,
hostport,
body_buffer);
} else {
sprintf(out_buffer,
"GET /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"DNT: 1\r\n"
"Connection: keep-alive\r\n"
"\r\n",
local->encode_buffer,
hostport,
g_useragent[g_useragent_index]
);
}
//LOGI("http header: %s", out_buffer);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata + head_size, datalength - head_size);
outlength += datalength - head_size;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
if (body_buffer != NULL)
free(body_buffer);
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
return outlength;
}
int http_simple_server_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
time_t now;
struct tm *tm_now;
char datetime[200];
time(&now);
tm_now = localtime(&now);
strftime(datetime, 200, "%a, %d %b %Y %H:%M:%S GMT", tm_now);
sprintf(out_buffer,
"HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Encoding: gzip\r\nContent-Type: text/html\r\nDate: "
"%s"
"\r\nServer: nginx\r\nVary: Accept-Encoding\r\n\r\n",
datetime);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata, datalength);
outlength += datalength;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
return outlength;
}
int http_simple_client_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
*needsendback = 0;
if (local->has_recv_header) {
return datalength;
}
char* data_begin = strstr(encryptdata, "\r\n\r\n");
if (data_begin) {
int outlength;
data_begin += 4;
local->has_recv_header = 1;
outlength = datalength - (data_begin - encryptdata);
memmove(encryptdata, data_begin, outlength);
return outlength;
} else {
return 0;
}
}
int http_simple_server_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
*needsendback = 0;
if (local->has_recv_header) {
return datalength;
}
if(datalength != 0)
{
local->recv_buffer = (char*)realloc(local->recv_buffer, local->recv_buffer_size + datalength);
memmove(local->recv_buffer + local->recv_buffer_size, encryptdata, datalength);
local->recv_buffer_size += datalength;
int outlength = local->recv_buffer_size;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, local->recv_buffer, local->recv_buffer_size);
}
if(local->recv_buffer_size > 10)
{
if(strstr(local->recv_buffer, "GET /") == local->recv_buffer || strstr(local->recv_buffer, "POST /") == local->recv_buffer)
{
if(local->recv_buffer_size > 65536)
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: over size");
return -1;
}
}
else
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: not match begin");
return -1;
}
}
else
{
LOGE("http_simple: too short");
local->has_sent_header = 1;
local->has_recv_header = 1;
return -1;
}
char* data_begin = strstr(encryptdata, "\r\n\r\n");
if (data_begin) {
int outlength;
char *ret_buf = (char*)malloc(*capacity);
memset(ret_buf, 0x00, *capacity);
int ret_buf_len = 0;
ret_buf_len = get_data_from_http_header(encryptdata, &ret_buf);
if (self->server.param && strlen(self->server.param) == 0)
{
self->server.param = NULL;
}
else
{
if(local->host_matched == 0)
{
char *host = (char*)malloc(1024);
get_host_from_http_header(local->recv_buffer, &host);
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos = 0;
int is_match = 0;
char * body_buffer = NULL;
strncpy(hosts, self->server.param, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
for(pos = 0; pos < host_num; pos++)
{
if(strcmp(phost[pos], host) == 0)
{
is_match = 1;
local->host_matched = 1;
}
}
if(is_match == 0)
{
free(local->recv_buffer);
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
local->has_sent_header = 1;
local->has_recv_header = 1;
LOGE("http_simple: not match host, host: %s", host);
return -1;
}
free(host);
}
}
if(ret_buf_len <= 0)
{
return -1;
}
data_begin += 4;
local->has_recv_header = 1;
ret_buf = (char*)realloc(ret_buf, ret_buf_len + datalength - (data_begin - encryptdata));
outlength = ret_buf_len + datalength - (data_begin - encryptdata);
memcpy(ret_buf + ret_buf_len, data_begin, datalength - (data_begin - encryptdata));
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, ret_buf, outlength);
free(ret_buf);
return outlength;
} else {
return 0;
}
}
void boundary(char result[])
{
char *str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
int i,lstr;
char ss[3] = {0};
lstr = strlen(str);
srand((unsigned int)time((time_t *)NULL));
for(i = 0; i < 32; ++i)
{
sprintf(ss, "%c", str[(rand()%lstr)]);
strcat(result, ss);
}
}
int http_post_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
http_simple_local_data *local = (http_simple_local_data*)self->l_data;
if (local->has_sent_header) {
return datalength;
}
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos;
char hostport[128];
int head_size = self->server.head_len + (xorshift128plus() & 0x3F);
int outlength;
char * out_buffer = (char*)malloc(datalength + 2048);
char * body_buffer = NULL;
if (head_size > datalength)
head_size = datalength;
http_simple_encode_head(local, encryptdata, head_size);
if (self->server.param && strlen(self->server.param) == 0)
self->server.param = NULL;
strncpy(hosts, self->server.param ? self->server.param : self->server.host, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
hosts[pos] = 0;
} else if (hosts[pos] == '#') {
char * body_pointer = &hosts[pos + 1];
char * p;
int trans_char = 0;
p = body_buffer = (char*)malloc(2048);
for ( ; *body_pointer; ++body_pointer) {
if (*body_pointer == '\\') {
trans_char = 1;
continue;
} else if (*body_pointer == '\n') {
*p = '\r';
*++p = '\n';
continue;
}
if (trans_char) {
if (*body_pointer == '\\' ) {
*p = '\\';
} else if (*body_pointer == 'n' ) {
*p = '\r';
*++p = '\n';
} else {
*p = '\\';
*p = *body_pointer;
}
trans_char = 0;
} else {
*p = *body_pointer;
}
++p;
}
*p = 0;
hosts[pos] = 0;
break;
}
}
host_num = xorshift128plus() % host_num;
if (self->server.port == 80)
sprintf(hostport, "%s", phost[host_num]);
else
sprintf(hostport, "%s:%d", phost[host_num], self->server.port);
if (body_buffer) {
sprintf(out_buffer,
"POST /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"%s\r\n\r\n",
local->encode_buffer,
hostport,
body_buffer);
} else {
char result[33] = {0};
boundary(result);
sprintf(out_buffer,
"POST /%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: en-US,en;q=0.8\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"Content-Type: multipart/form-data; boundary=%s\r\n"
"DNT: 1\r\n"
"Connection: keep-alive\r\n"
"\r\n",
local->encode_buffer,
hostport,
g_useragent[g_useragent_index],
result
);
}
//LOGI("http header: %s", out_buffer);
outlength = strlen(out_buffer);
memmove(out_buffer + outlength, encryptdata + head_size, datalength - head_size);
outlength += datalength - head_size;
local->has_sent_header = 1;
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, outlength);
free(out_buffer);
if (body_buffer != NULL)
free(body_buffer);
if (local->encode_buffer != NULL) {
free(local->encode_buffer);
local->encode_buffer = NULL;
}
return outlength;
}

View File

@ -0,0 +1,21 @@
/*
* http_simple.h - Define shadowsocksR server's buffers and callbacks
*
* Copyright (C) 2015 - 2016, Break Wa11 <mmgac001@gmail.com>
*/
#ifndef _HTTP_SIMPLE_H
#define _HTTP_SIMPLE_H
obfs * http_simple_new_obfs();
void http_simple_dispose(obfs *self);
int http_simple_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity);
int http_simple_client_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback);
int http_post_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity);
int http_simple_server_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity);
int http_simple_server_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback);
#endif // _HTTP_SIMPLE_H

View File

@ -0,0 +1,260 @@
/*
* jconf.c - Parse the JSON format config file
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "utils.h"
#include "jconf.h"
#include "json.h"
#include "string.h"
#include <libcork/core.h>
#define check_json_value_type(value, expected_type, message) \
do { \
if ((value)->type != (expected_type)) \
FATAL((message)); \
} while(0)
static char *
to_string(const json_value *value)
{
if (value->type == json_string) {
return ss_strndup(value->u.string.ptr, value->u.string.length);
} else if (value->type == json_integer) {
return strdup(ss_itoa(value->u.integer));
} else if (value->type == json_null) {
return "null";
} else {
LOGE("%d", value->type);
FATAL("Invalid config format.");
}
return 0;
}
void
free_addr(ss_addr_t *addr)
{
ss_free(addr->host);
ss_free(addr->port);
}
void
parse_addr(const char *str, ss_addr_t *addr)
{
int ipv6 = 0, ret = -1, n = 0;
char *pch;
struct cork_ip ip;
if (cork_ip_init(&ip, str) != -1) {
addr->host = strdup(str);
addr->port = NULL;
return;
}
pch = strchr(str, ':');
while (pch != NULL) {
n++;
ret = pch - str;
pch = strchr(pch + 1, ':');
}
if (n > 1) {
ipv6 = 1;
if (str[ret - 1] != ']') {
ret = -1;
}
}
if (ret == -1) {
if (ipv6) {
addr->host = ss_strndup(str + 1, strlen(str) - 2);
} else {
addr->host = strdup(str);
}
addr->port = NULL;
} else {
if (ipv6) {
addr->host = ss_strndup(str + 1, ret - 2);
} else {
addr->host = ss_strndup(str, ret);
}
addr->port = strdup(str + ret + 1);
}
}
jconf_t *
read_jconf(const char *file)
{
static jconf_t conf;
memset(&conf, 0, sizeof(jconf_t));
char *buf;
json_value *obj;
FILE *f = fopen(file, "rb");
if (f == NULL) {
FATAL("Invalid config path.");
}
fseek(f, 0, SEEK_END);
long pos = ftell(f);
fseek(f, 0, SEEK_SET);
if (pos >= MAX_CONF_SIZE) {
FATAL("Too large config file.");
}
buf = ss_malloc(pos + 1);
if (buf == NULL) {
FATAL("No enough memory.");
}
int nread = fread(buf, pos, 1, f);
if (!nread) {
FATAL("Failed to read the config file.");
}
fclose(f);
buf[pos] = '\0'; // end of string
json_settings settings = { 0UL, 0, NULL, NULL, NULL };
char error_buf[512];
obj = json_parse_ex(&settings, buf, pos, error_buf);
if (obj == NULL) {
FATAL(error_buf);
}
if (obj->type == json_object) {
unsigned int i, j;
for (i = 0; i < obj->u.object.length; i++) {
char *name = obj->u.object.values[i].name;
json_value *value = obj->u.object.values[i].value;
if (strcmp(name, "server") == 0) {
if (value->type == json_array) {
for (j = 0; j < value->u.array.length; j++) {
if (j >= MAX_REMOTE_NUM) {
break;
}
json_value *v = value->u.array.values[j];
char *addr_str = to_string(v);
parse_addr(addr_str, conf.remote_addr + j);
ss_free(addr_str);
conf.remote_num = j + 1;
}
} else if (value->type == json_string) {
conf.remote_addr[0].host = to_string(value);
conf.remote_addr[0].port = NULL;
conf.remote_num = 1;
}
} else if (strcmp(name, "port_password") == 0) {
if (value->type == json_object) {
for (j = 0; j < value->u.object.length; j++) {
if (j >= MAX_PORT_NUM) {
break;
}
json_value *v = value->u.object.values[j].value;
if (v->type == json_string) {
conf.port_password[j].port = ss_strndup(value->u.object.values[j].name,
value->u.object.values[j].name_length);
conf.port_password[j].password = to_string(v);
conf.port_password_num = j + 1;
}
}
}
} else if (strcmp(name, "server_port") == 0) {
conf.remote_port = to_string(value);
} else if (strcmp(name, "local_address") == 0) {
conf.local_addr = to_string(value);
} else if (strcmp(name, "local_port") == 0) {
conf.local_port = to_string(value);
} else if (strcmp(name, "password") == 0) {
conf.password = to_string(value);
} else if (strcmp(name, "protocol") == 0) { // SSR
conf.protocol = to_string(value);
} else if (strcmp(name, "protocol_param") == 0) { // SSR
conf.protocol_param = to_string(value);
} else if (strcmp(name, "method") == 0) {
conf.method = to_string(value);
} else if (strcmp(name, "obfs") == 0) { // SSR
conf.obfs = to_string(value);
} else if (strcmp(name, "obfs_param") == 0) { // SSR
conf.obfs_param = to_string(value);
} else if (strcmp(name, "timeout") == 0) {
conf.timeout = to_string(value);
} else if (strcmp(name, "user") == 0) {
conf.user = to_string(value);
} else if (strcmp(name, "fast_open") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'fast_open' must be a boolean");
conf.fast_open = value->u.boolean;
} else if (strcmp(name, "auth") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'auth' must be a boolean");
conf.auth = value->u.boolean;
} else if (strcmp(name, "nofile") == 0) {
check_json_value_type(value, json_integer,
"invalid config file: option 'nofile' must be an integer");
conf.nofile = value->u.integer;
} else if (strcmp(name, "nameserver") == 0) {
conf.nameserver = to_string(value);
} else if (strcmp(name, "tunnel_address") == 0) {
conf.tunnel_address = to_string(value);
} else if (strcmp(name, "mode") == 0) {
char *mode_str = to_string(value);
if (strcmp(mode_str, "tcp_only") == 0)
conf.mode = TCP_ONLY;
else if (strcmp(mode_str, "tcp_and_udp") == 0)
conf.mode = TCP_AND_UDP;
else if (strcmp(mode_str, "udp_only") == 0)
conf.mode = UDP_ONLY;
else
LOGI("ignore unknown mode: %s, use tcp_only as fallback",
mode_str);
ss_free(mode_str);
} else if (strcmp(name, "mtu") == 0) {
check_json_value_type(value, json_integer,
"invalid config file: option 'mtu' must be an integer");
conf.mtu = value->u.integer;
} else if (strcmp(name, "mptcp") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'mptcp' must be a boolean");
conf.mptcp = value->u.boolean;
} else if (strcmp(name, "ipv6_first") == 0) {
check_json_value_type(value, json_boolean,
"invalid config file: option 'ipv6_first' must be a boolean");
conf.ipv6_first = value->u.boolean;
}
}
} else {
FATAL("Invalid config file");
}
ss_free(buf);
json_value_free(obj);
return &conf;
}

View File

@ -0,0 +1,78 @@
/*
* jconf.h - Define the config data structure
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _JCONF_H
#define _JCONF_H
#define MAX_PORT_NUM 1024
#define MAX_REMOTE_NUM 10
#define MAX_CONF_SIZE 128 * 1024
#define MAX_DNS_NUM 4
#define MAX_CONNECT_TIMEOUT 10
#define MAX_REQUEST_TIMEOUT 60
#define MIN_UDP_TIMEOUT 10
#define TCP_ONLY 0
#define TCP_AND_UDP 1
#define UDP_ONLY 3
typedef struct {
char *host;
char *port;
} ss_addr_t;
typedef struct {
char *port;
char *password;
} ss_port_password_t;
typedef struct {
int remote_num;
ss_addr_t remote_addr[MAX_REMOTE_NUM];
int port_password_num;
ss_port_password_t port_password[MAX_PORT_NUM];
char *remote_port;
char *local_addr;
char *local_port;
char *password;
char *protocol; // SSR
char *protocol_param; // SSR
char *method;
char *obfs; // SSR
char *obfs_param; // SSR
char *timeout;
char *user;
int auth;
int fast_open;
int nofile;
char *nameserver;
char *tunnel_address;
int mode;
int mtu;
int mptcp;
int ipv6_first;
} jconf_t;
jconf_t *read_jconf(const char *file);
void parse_addr(const char *str, ss_addr_t *addr);
void free_addr(ss_addr_t *addr);
#endif // _JCONF_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _JSON_H
#define _JSON_H
#ifndef json_char
#define json_char char
#endif
#ifndef json_int_t
#ifndef _MSC_VER
#include <inttypes.h>
#define json_int_t int64_t
#else
#define json_int_t __int64
#endif
#endif
#include <stdlib.h>
#ifdef __cplusplus
#include <string.h>
extern "C"
{
#endif
typedef struct {
unsigned long max_memory;
int settings;
/* Custom allocator support (leave null to use malloc/free)
*/
void * (*mem_alloc)(size_t, int zero, void *user_data);
void (*mem_free)(void *, void *user_data);
void *user_data; /* will be passed to mem_alloc and mem_free */
} json_settings;
#define json_enable_comments 0x01
typedef enum {
json_none,
json_object,
json_array,
json_integer,
json_double,
json_string,
json_boolean,
json_null
} json_type;
extern const struct _json_value json_value_none;
typedef struct _json_value {
struct _json_value *parent;
json_type type;
union {
int boolean;
json_int_t integer;
double dbl;
struct {
unsigned int length;
json_char *ptr; /* null terminated */
} string;
struct {
unsigned int length;
struct {
json_char *name;
unsigned int name_length;
struct _json_value *value;
} *values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin() const
{
return values;
}
decltype(values) end() const
{
return values + length;
}
#endif
} object;
struct {
unsigned int length;
struct _json_value **values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin() const
{
return values;
}
decltype(values) end() const
{
return values + length;
}
#endif
} array;
} u;
union {
struct _json_value *next_alloc;
void *object_mem;
} _reserved;
/* Some C++ operator sugar */
#ifdef __cplusplus
public:
inline _json_value(){
memset(this, 0, sizeof(_json_value));
}
inline const struct _json_value &operator [] (int index) const {
if (type != json_array || index < 0
|| ((unsigned int)index) >= u.array.length) {
return json_value_none;
}
return *u.array.values[index];
}
inline const struct _json_value &operator [] (const char *index) const {
if (type != json_object) {
return json_value_none;
}
for (unsigned int i = 0; i < u.object.length; ++i)
if (!strcmp(u.object.values[i].name, index)) {
return *u.object.values[i].value;
}
return json_value_none;
}
inline operator const char * () const
{
switch (type) {
case json_string:
return u.string.ptr;
default:
return "";
}
}
inline operator
json_int_t() const
{
switch (type) {
case json_integer:
return u.integer;
case json_double:
return (json_int_t)u.dbl;
default:
return 0;
}
}
inline operator
bool() const
{
if (type != json_boolean) {
return false;
}
return u.boolean != 0;
}
inline operator double () const
{
switch (type) {
case json_integer:
return (double)u.integer;
case json_double:
return u.dbl;
default:
return 0;
}
}
#endif
} json_value;
json_value *json_parse(const json_char *json,
size_t length);
#define json_error_max 128
json_value *json_parse_ex(json_settings *settings,
const json_char *json,
size_t length,
char *error);
void json_value_free(json_value *);
/* Not usually necessary, unless you used a custom mem_alloc and now want to
* use a custom mem_free.
*/
void json_value_free_ex(json_settings *settings,
json_value *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -0,0 +1,370 @@
#include "list.h"
/// 文件list_impl.c
/// 功能:实现链表的基本操作
/// 作者bluewind
/// 完成时间2011.5.29
/// 修改时间2011.5.31, 2011.7.2
/// 修改备注:在头节点处添加一个空节点,可以优化添加、删除节点代码
/// 再次修改链表增加节点数据data_size限制数据大小修改了
/// 添加复制数据代码修正重复添加节点后释放节点的Bug添加了前
/// 插、排序和遍历功能7.3 添加tail尾指针改进后插法性能并改名
/// --------------------------------------------------------------
void swap_data(Node n1, Node n2);
/// --------------------------------------------------------------
// 函数名list_init
// 功能: 链表初始化
// 参数: 无
// 返回值:已初始化链表指针
// 备注: 链表本身动态分配由list_destroy函数管理释放
/// --------------------------------------------------------------
List list_init(unsigned int data_size)
{
List list = (List) malloc(sizeof(struct clist));
if(list != NULL) //内存分配成功
{
list->head = (Node) malloc(sizeof(node)); //为头节点分配内存
if(list->head) //内存分配成功
{
list->head->data = NULL; //初始化头节点
list->head->next = NULL;
list->data_size = data_size;
list->tail = list->head;
list->size = 0;
list->add_back = list_add_back; //初始化成员函数
list->add_front = list_add_front;
list->delete_node = list_delete_node;
list->delete_at = list_delete_at;
list->modify_at = list_modify_at;
list->have_same = list_have_same;
list->have_same_cmp = list_have_same_cmp;
list->foreach = list_foreach;
list->clear = list_clear;
list->sort = list_sort;
list->destroy = list_destroy;
}
}
return list;
}
/// --------------------------------------------------------------
// 函数名list_add_back
// 功能: 添加链表结点 (后插法)
// 参数: l--链表指针data--链表数据指针,可为任意类型
// 返回值int型为1表示添加成功为0表示添加失败
// 备注: 如果链表本身为空或是分配节点内存失败将返回0
/// --------------------------------------------------------------
int list_add_back(List l, void *data)
{
Node new_node = (Node) malloc(sizeof(node));
if(l != NULL && new_node != NULL) //链表本身不为空,且内存申请成功
{
new_node->data = malloc(l->data_size);
memcpy(new_node->data, data, l->data_size);
new_node->next = NULL;
l->tail->next = new_node; //添加节点
l->tail = new_node; //记录尾节点位置
l->size ++; //链表元素总数加1
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函数名list_add_front
// 功能: 添加链表结点 (前插法)
// 参数: l--链表指针data--链表数据指针,可为任意类型
// 返回值int型为1表示添加成功为0表示添加失败
// 备注: 如果链表本身为空或是分配节点内存失败将返回0
/// --------------------------------------------------------------
int list_add_front(List l, void *data)
{
Node new_node = (Node) malloc(sizeof(node));
if(l != NULL && new_node != NULL)
{
new_node->data = malloc(l->data_size);
memcpy(new_node->data, data, l->data_size);
new_node->next = l->head->next;
l->head->next = new_node;
if(!l->size) //记录尾指针位置
l->tail = new_node;
l->size ++;
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函数名list_delete_node
// 功能:删除链表结点
// 参数l--链表指针data--链表数据指针,可为任意类型
// *pfunc为指向一个数据类型比较的函数指针
// 返回值int型为1表示删除成功为0表示没有找到匹配数据
// 备注:*pfunc函数接口参数ndata为节点数据data为比较数据返回为真表示匹配数据
/// --------------------------------------------------------------
int list_delete_node(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
if(l != NULL)
{
Node prev = l->head; //前一个节点
Node curr = l->head->next; //当前节点
while(curr != NULL)
{
if(pfunc(curr->data, data)) //如果找到匹配数据
{
if(curr == l->tail) //如果是删除尾节点
l->tail = prev;
prev->next = prev->next->next; //修改前节点next指针指向下下个节点
free(curr->data); //释放节点数据
free(curr); //释放节点
l->size--; //链表元素总数减1
return 1; //返回真值
}
prev = prev->next; //没有找到匹配时移动前节点和当前节点
curr = curr->next;
}
}
return 0; //没有找到匹配数据
}
/// --------------------------------------------------------------
// 函数名list_delete_at
// 功能: 修改链表节点元素值
// 参数: l--链表指针index--索引值, 范围(0 -- size-1)
// 返回值int型为1表示删除成功为0表示删除失败
// 备注: 如果链表本身为空或是index为非法值将返回0
/// --------------------------------------------------------------
int list_delete_at(List l, unsigned int index)
{
unsigned int cindex = 0;
if(l != NULL && index >= 0 && index < l->size)
{
Node prev = l->head; //前一个节点
Node curr = l->head->next; //当前节点
while(cindex != index)
{
prev = prev->next;
curr = curr->next;
cindex ++;
}
if(index == (l->size) - 1)
l->tail = prev;
prev->next = prev->next->next;
free(curr->data);
free(curr);
l->size --;
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函数名list_modify_at
// 功能: 修改链表节点元素值
// 参数: l--链表指针index--索引值, 范围(0 -- size-1)
// data--链表数据指针
// 返回值int型为1表示修改成功为0表示修改失败
// 备注: 如果链表本身为空或是index为非法值将返回0
/// --------------------------------------------------------------
int list_modify_at(List l, unsigned int index, void *new_data)
{
unsigned int cindex = 0;
if(l != NULL && index >= 0 && index < l->size ) //非空链表并且index值合法
{
Node curr = l->head->next;
while(cindex != index)
{
curr = curr->next;
cindex ++;
}
memcpy(curr->data, new_data, l->data_size);
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函数名list_sort
// 功能: 链表排序
// 参数: l--链表指针,*pfunc为指向一个数据类型比较的函数指针
// 返回值:无
// 备注: 使用简单选择排序法,相比冒泡法每次交换,效率高一点
/// --------------------------------------------------------------
void list_sort(List l, compare pfunc)
{
if(l != NULL)
{
Node min, icurr, jcurr;
icurr = l->head->next;
while(icurr)
{
min = icurr; //记录最小值
jcurr = icurr->next; //内循环指向下一个节点
while(jcurr)
{
if(pfunc(min->data, jcurr->data)) //如果找到n+1到最后一个元素最小值
min = jcurr; //记录下最小值的位置
jcurr = jcurr->next;
}
if(min != icurr) //当最小值位置和n+1元素位置不相同时
{
swap_data(min, icurr); //才进行交换,减少交换次数
}
icurr = icurr->next;
}
}
}
void swap_data(Node n1, Node n2)
{
void *temp;
temp = n2->data;
n2->data = n1->data;
n1->data = temp;
}
int list_have_same(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
if(l != NULL)
{
Node curr;
for(curr = l->head->next; curr != NULL; curr = curr->next)
{
if(pfunc(curr->data, data))
{
return 1;
}
}
}
return 0;
}
int list_have_same_cmp(List l, void *data)
{
if(l != NULL)
{
Node curr;
for(curr = l->head->next; curr != NULL; curr = curr->next)
{
if(memcmp(curr->data, data, l->data_size))
{
return 1;
}
}
}
return 0;
}
/// --------------------------------------------------------------
// 函数名list_foreach
// 功能: 遍历链表元素
// 参数: l--链表指针doit为指向一个处理数据的函数指针
// 返回值:无
// 备注: doit申明为void (*dofunc)(void *ndata)原型
/// --------------------------------------------------------------
void list_foreach(List l, dofunc doit)
{
if(l != NULL)
{
Node curr;
for(curr = l->head->next; curr != NULL; curr = curr->next)
{
doit(curr->data);
}
}
}
/// --------------------------------------------------------------
// 函数名list_clear
// 功能: 清空链表元素
// 参数: l--链表指针
// 返回值:无
// 备注: 没有使用先Destroy再Init链表的办法直接实现
/// --------------------------------------------------------------
void list_clear(List l)
{
if(l != NULL)
{
Node temp;
Node curr = l->head->next;
while(curr != NULL)
{
temp = curr->next;
free(curr->data); //释放节点和数据
free(curr);
curr = temp;
}
l->size = 0; //重置链表数据
l->head->next = NULL;
l->tail = l->head;
}
}
/// --------------------------------------------------------------
// 函数名list_destroy
// 功能: 释放链表
// 参数: l--链表指针
// 返回值:空链表指针
/// --------------------------------------------------------------
List list_destroy(List l)
{
if(l != NULL)
{
Node temp;
while(l->head)
{
temp = l->head->next;
if(l->head->data != NULL) //如果是头节点就不释放数据空间
free(l->head->data); //先释放节点数据(但是节点数据里也有指针?)
free(l->head); //再释放节点
l->head = temp;
}
free(l); //释放链表本身占用空间
l = NULL;
}
return l;
}

View File

@ -0,0 +1,61 @@
#ifndef LIST_H_H
#define LIST_H_H
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct clist *List;
typedef int (*compare)(void *ndata, void *data);
typedef void (*dofunc)(void *ndata);
typedef int (*lpf0)(List l, void *data);
typedef int (*lpf1)(List l, void *data, compare pfunc);
typedef List (*lpf2)(List l);
typedef void (*lpf3)(List l);
typedef void (*lpf4)(List l, dofunc pfunc);
typedef int (*lpf5)(List l, unsigned int index, void *new_data);
typedef void (*lpf6)(List l, compare pfunc);
typedef int (*lpf7)(List l, unsigned int index);
typedef struct cnode
{
void *data;
struct cnode *next;
}node, *Node;
typedef struct clist
{
Node head;
Node tail;
unsigned int size;
unsigned int data_size;
lpf0 add_back;
lpf0 add_front;
lpf1 delete_node;
lpf1 have_same;
lpf0 have_same_cmp;
lpf4 foreach;
lpf3 clear;
lpf2 destroy;
lpf5 modify_at;
lpf6 sort;
lpf7 delete_at;
}list;
//初始化链表
List list_init(unsigned int data_size);
int list_add_back(List l, void *data);
int list_add_front(List l, void *data);
int list_delete_node(List l, void *data, compare pfunc);
int list_delete_at(List l, unsigned int index);
int list_modify_at(List l, unsigned int index, void *new_data);
int list_have_same(List l, void *data, compare pfunc);
int list_have_same_cmp(List l, void *data);
void list_foreach(List l, dofunc doit);
void list_sort(List l, compare pfunc);
void list_clear(List l);
//释放链表
List list_destroy(List l);
#endif

View File

@ -0,0 +1,297 @@
/*
* netutils.c - Network utilities
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <libcork/core.h>
#include <udns.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __MINGW32__
#include "win32.h"
#define sleep(n) Sleep(1000 * (n))
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__)
#include <net/if.h>
#include <sys/ioctl.h>
#define SET_INTERFACE
#endif
#include "netutils.h"
#include "utils.h"
#ifndef SO_REUSEPORT
#define SO_REUSEPORT 15
#endif
extern int verbose;
static const char valid_label_bytes[] =
"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
#if defined(MODULE_LOCAL)
extern int keep_resolving;
#endif
int
set_reuseport(int socket)
{
int opt = 1;
return setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
}
size_t
get_sockaddr_len(struct sockaddr *addr)
{
if (addr->sa_family == AF_INET) {
return sizeof(struct sockaddr_in);
} else if (addr->sa_family == AF_INET6) {
return sizeof(struct sockaddr_in6);
}
return 0;
}
#ifdef SET_INTERFACE
int
setinterface(int socket_fd, const char *interface_name)
{
struct ifreq interface;
memset(&interface, 0, sizeof(struct ifreq));
strncpy(interface.ifr_name, interface_name, IFNAMSIZ);
int res = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, &interface,
sizeof(struct ifreq));
return res;
}
#endif
int
bind_to_address(int socket_fd, const char *host)
{
if (host != NULL) {
struct cork_ip ip;
struct sockaddr_storage storage;
memset(&storage, 0, sizeof(struct sockaddr_storage));
if (cork_ip_init(&ip, host) != -1) {
if (ip.version == 4) {
struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
dns_pton(AF_INET, host, &addr->sin_addr);
addr->sin_family = AF_INET;
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
} else if (ip.version == 6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
dns_pton(AF_INET6, host, &addr->sin6_addr);
addr->sin6_family = AF_INET6;
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6));
}
}
}
return -1;
}
ssize_t
get_sockaddr(char *host, char *port,
struct sockaddr_storage *storage, int block,
int ipv6first)
{
struct cork_ip ip;
if (cork_ip_init(&ip, host) != -1) {
if (ip.version == 4) {
struct sockaddr_in *addr = (struct sockaddr_in *)storage;
addr->sin_family = AF_INET;
dns_pton(AF_INET, host, &(addr->sin_addr));
if (port != NULL) {
addr->sin_port = htons(atoi(port));
}
} else if (ip.version == 6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
addr->sin6_family = AF_INET6;
dns_pton(AF_INET6, host, &(addr->sin6_addr));
if (port != NULL) {
addr->sin6_port = htons(atoi(port));
}
}
return 0;
} else {
struct addrinfo hints;
struct addrinfo *result, *rp;
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 */
int err, i;
for (i = 1; i < 8; i++) {
err = getaddrinfo(host, port, &hints, &result);
#if defined(MODULE_LOCAL)
if (!keep_resolving)
break;
#endif
if ((!block || !err)) {
break;
} else {
sleep(pow(2, i));
LOGE("failed to resolve server name, wait %.0f seconds", pow(2, i));
}
}
if (err != 0) {
LOGE("getaddrinfo: %s", gai_strerror(err));
return -1;
}
int prefer_af = ipv6first ? AF_INET6 : AF_INET;
for (rp = result; rp != NULL; rp = rp->ai_next)
if (rp->ai_family == prefer_af) {
if (rp->ai_family == AF_INET)
memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
else if (rp->ai_family == AF_INET6)
memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
break;
}
if (rp == NULL) {
for (rp = result; rp != NULL; rp = rp->ai_next) {
if (rp->ai_family == AF_INET)
memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in));
else if (rp->ai_family == AF_INET6)
memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6));
break;
}
}
if (rp == NULL) {
LOGE("failed to resolve remote addr");
return -1;
}
freeaddrinfo(result);
return 0;
}
return -1;
}
int
sockaddr_cmp(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len)
{
struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1;
struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2;
struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1;
struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2;
if (p1_in->sin_family < p2_in->sin_family)
return -1;
if (p1_in->sin_family > p2_in->sin_family)
return 1;
/* compare ip4 */
if (p1_in->sin_family == AF_INET) {
/* just order it, ntohs not required */
if (p1_in->sin_port < p2_in->sin_port)
return -1;
if (p1_in->sin_port > p2_in->sin_port)
return 1;
return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
} else if (p1_in6->sin6_family == AF_INET6) {
/* just order it, ntohs not required */
if (p1_in6->sin6_port < p2_in6->sin6_port)
return -1;
if (p1_in6->sin6_port > p2_in6->sin6_port)
return 1;
return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
INET6_SIZE);
} else {
/* eek unknown type, perform this comparison for sanity. */
return memcmp(addr1, addr2, len);
}
}
int
sockaddr_cmp_addr(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len)
{
struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1;
struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2;
struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1;
struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2;
if (p1_in->sin_family < p2_in->sin_family)
return -1;
if (p1_in->sin_family > p2_in->sin_family)
return 1;
/* compare ip4 */
if (p1_in->sin_family == AF_INET) {
return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
} else if (p1_in6->sin6_family == AF_INET6) {
return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
INET6_SIZE);
} else {
/* eek unknown type, perform this comparison for sanity. */
return memcmp(addr1, addr2, len);
}
}
int
validate_hostname(const char *hostname, const int hostname_len)
{
if (hostname == NULL)
return 0;
if (hostname_len < 1 || hostname_len > 255)
return 0;
if (hostname[0] == '.')
return 0;
const char *label = hostname;
while (label < hostname + hostname_len) {
size_t label_len = hostname_len - (label - hostname);
char *next_dot = strchr(label, '.');
if (next_dot != NULL)
label_len = next_dot - label;
if (label + label_len > hostname + hostname_len)
return 0;
if (label_len > 63 || label_len < 1)
return 0;
if (label[0] == '-' || label[label_len - 1] == '-')
return 0;
if (strspn(label, valid_label_bytes) < label_len)
return 0;
label += label_len + 1;
}
return 1;
}

View File

@ -0,0 +1,98 @@
/*
* netutils.h - Network utilities
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _NETUTILS_H
#define _NETUTILS_H
#if defined(__linux__)
#include <netdb.h>
#elif !defined(__MINGW32__)
#include <netinet/tcp.h>
#endif
// only enable TCP_FASTOPEN on linux
#if defined(__linux__)
#include <linux/tcp.h>
/* conditional define for TCP_FASTOPEN */
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
#endif
/* conditional define for MSG_FASTOPEN */
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#elif !defined(__APPLE__)
#ifdef TCP_FASTOPEN
#undef TCP_FASTOPEN
#endif
#endif
/* Backward compatibility for MPTCP_ENABLED between kernel 3 & 4 */
#ifndef MPTCP_ENABLED
#ifdef TCP_CC_INFO
#define MPTCP_ENABLED 42
#else
#define MPTCP_ENABLED 26
#endif
#endif
/** byte size of ip4 address */
#define INET_SIZE 4
/** byte size of ip6 address */
#define INET6_SIZE 16
size_t get_sockaddr_len(struct sockaddr *addr);
ssize_t get_sockaddr(char *host, char *port,
struct sockaddr_storage *storage, int block,
int ipv6first);
int set_reuseport(int socket);
#ifdef SET_INTERFACE
int setinterface(int socket_fd, const char *interface_name);
#endif
int bind_to_address(int socket_fd, const char *address);
/**
* Compare two sockaddrs. Imposes an ordering on the addresses.
* Compares address and port.
* @param addr1: address 1.
* @param addr2: address 2.
* @param len: lengths of addr.
* @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
*/
int sockaddr_cmp(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len);
/**
* Compare two sockaddrs. Compares address, not the port.
* @param addr1: address 1.
* @param addr2: address 2.
* @param len: lengths of addr.
* @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
*/
int sockaddr_cmp_addr(struct sockaddr_storage *addr1,
struct sockaddr_storage *addr2, socklen_t len);
int validate_hostname(const char *hostname, const int hostname_len);
#endif

View File

@ -0,0 +1,205 @@
#include <string.h>
#include <stdlib.h>
#include "utils.h"
#include "obfs.h"
int rand_bytes(uint8_t *output, int len);
#define OBFS_HMAC_SHA1_LEN 10
#include "obfsutil.c"
#include "crc32.c"
#include "base64.c"
#include "http_simple.c"
#include "tls1.2_ticket.c"
#include "verify.c"
#include "auth.c"
void * init_data() {
return malloc(1);
}
obfs * new_obfs() {
obfs * self = (obfs*)malloc(sizeof(obfs));
self->l_data = NULL;
return self;
}
void set_server_info(obfs *self, server_info *server) {
memmove(&self->server, server, sizeof(server_info));
}
void get_server_info(obfs *self, server_info *server) {
memmove(server, &self->server, sizeof(server_info));
}
void dispose_obfs(obfs *self) {
free(self);
}
obfs_class * new_obfs_class(char *plugin_name)
{
if (plugin_name == NULL)
return NULL;
if (strcmp(plugin_name, "origin") == 0)
return NULL;
if (strcmp(plugin_name, "plain") == 0)
return NULL;
init_crc32_table();
init_shift128plus();
if (strcmp(plugin_name, "http_simple") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = init_data;
plugin->new_obfs = http_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = http_simple_dispose;
plugin->client_encode = http_simple_client_encode;
plugin->client_decode = http_simple_client_decode;
plugin->server_encode = http_simple_server_encode;
plugin->server_decode = http_simple_server_decode;
return plugin;
} else if (strcmp(plugin_name, "http_post") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = init_data;
plugin->new_obfs = http_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = http_simple_dispose;
plugin->client_encode = http_post_client_encode;
plugin->client_decode = http_simple_client_decode;
plugin->server_encode = http_simple_server_encode;
plugin->server_decode = http_simple_server_decode;
return plugin;
} else if (strcmp(plugin_name, "tls1.2_ticket_auth") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = tls12_ticket_auth_init_data;
plugin->new_obfs = tls12_ticket_auth_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = tls12_ticket_auth_dispose;
plugin->client_encode = tls12_ticket_auth_client_encode;
plugin->client_decode = tls12_ticket_auth_client_decode;
plugin->server_encode = tls12_ticket_auth_server_encode;
plugin->server_decode = tls12_ticket_auth_server_decode;
return plugin;
} else if (strcmp(plugin_name, "verify_simple") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = init_data;
plugin->new_obfs = verify_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = verify_simple_dispose;
plugin->client_pre_encrypt = verify_simple_client_pre_encrypt;
plugin->client_post_decrypt = verify_simple_client_post_decrypt;
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
plugin->server_pre_encrypt = verify_simple_server_pre_encrypt;
plugin->server_post_decrypt = verify_simple_server_post_decrypt;
plugin->server_udp_pre_encrypt = NULL;
plugin->server_udp_post_decrypt = NULL;
return plugin;
} else if (strcmp(plugin_name, "auth_simple") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_simple_client_pre_encrypt;
plugin->client_post_decrypt = auth_simple_client_post_decrypt;
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
return plugin;
} else if (strcmp(plugin_name, "auth_sha1") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_sha1_client_pre_encrypt;
plugin->client_post_decrypt = auth_sha1_client_post_decrypt;
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
return plugin;
} else if (strcmp(plugin_name, "auth_sha1_v2") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_sha1_v2_client_pre_encrypt;
plugin->client_post_decrypt = auth_sha1_v2_client_post_decrypt;
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
return plugin;
} else if (strcmp(plugin_name, "auth_sha1_v4") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_simple_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_sha1_v4_client_pre_encrypt;
plugin->client_post_decrypt = auth_sha1_v4_client_post_decrypt;
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
return plugin;
} else if (strcmp(plugin_name, "auth_aes128_md5") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_aes128_md5_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_aes128_sha1_client_pre_encrypt;
plugin->client_post_decrypt = auth_aes128_sha1_client_post_decrypt;
plugin->client_udp_pre_encrypt = auth_aes128_sha1_client_udp_pre_encrypt;
plugin->client_udp_post_decrypt = auth_aes128_sha1_client_udp_post_decrypt;
return plugin;
} else if (strcmp(plugin_name, "auth_aes128_sha1") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs));
plugin->init_data = auth_simple_init_data;
plugin->new_obfs = auth_aes128_sha1_new_obfs;
plugin->get_server_info = get_server_info;
plugin->set_server_info = set_server_info;
plugin->dispose = auth_simple_dispose;
plugin->client_pre_encrypt = auth_aes128_sha1_client_pre_encrypt;
plugin->client_post_decrypt = auth_aes128_sha1_client_post_decrypt;
plugin->client_udp_pre_encrypt = auth_aes128_sha1_client_udp_pre_encrypt;
plugin->client_udp_post_decrypt = auth_aes128_sha1_client_udp_post_decrypt;
return plugin;
}
LOGE("Load obfs '%s' failed", plugin_name);
return NULL;
}
void free_obfs_class(obfs_class *plugin) {
free(plugin);
}

View File

@ -0,0 +1,100 @@
/*
* obfs.h - Define shadowsocksR server's buffers and callbacks
*
* Copyright (C) 2015 - 2016, Break Wa11 <mmgac001@gmail.com>
*/
#ifndef _OBFS_H
#define _OBFS_H
#include <stdint.h>
#include <unistd.h>
typedef struct server_info {
char host[64];
uint16_t port;
char *param;
void *g_data;
uint8_t *iv;
size_t iv_len;
uint8_t *recv_iv;
size_t recv_iv_len;
uint8_t *key;
size_t key_len;
int head_len;
size_t tcp_mss;
}server_info;
typedef struct obfs {
server_info server;
void *l_data;
}obfs;
typedef struct obfs_class {
void * (*init_data)();
obfs * (*new_obfs)();
void (*get_server_info)(obfs *self, server_info *server);
void (*set_server_info)(obfs *self, server_info *server);
void (*dispose)(obfs *self);
int (*client_pre_encrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*client_encode)(obfs *self,
char **pencryptdata,
int datalength,
size_t* capacity);
int (*client_decode)(obfs *self,
char **pencryptdata,
int datalength,
size_t* capacity,
int *needsendback);
int (*client_post_decrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*client_udp_pre_encrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*client_udp_post_decrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*server_pre_encrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*server_post_decrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*server_udp_pre_encrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*server_udp_post_decrypt)(obfs *self,
char **pplaindata,
int datalength,
size_t* capacity);
int (*server_encode)(obfs *self,
char **pencryptdata,
int datalength,
size_t* capacity);
int (*server_decode)(obfs *self,
char **pencryptdata,
int datalength,
size_t* capacity,
int *needsendback);
}obfs_class;
obfs_class * new_obfs_class(char *plugin_name);
void free_obfs_class(obfs_class *plugin);
void set_server_info(obfs *self, server_info *server);
void get_server_info(obfs *self, server_info *server);
obfs * new_obfs();
void dispose_obfs(obfs *self);
#endif // _OBFS_H

View File

@ -0,0 +1,36 @@
int get_head_size(char *plaindata, int size, int def_size) {
if (plaindata == NULL || size < 2)
return def_size;
int head_type = plaindata[0] & 0x7;
if (head_type == 1)
return 7;
if (head_type == 4)
return 19;
if (head_type == 3)
return 4 + plaindata[1];
return def_size;
}
static int shift128plus_init_flag = 0;
static uint64_t shift128plus_s[2] = {0x10000000, 0xFFFFFFFF};
void init_shift128plus(void) {
if (shift128plus_init_flag == 0) {
shift128plus_init_flag = 1;
uint32_t seed = time(NULL);
shift128plus_s[0] = seed | 0x100000000L;
shift128plus_s[1] = ((uint64_t)seed << 32) | 0x1;
}
}
uint64_t xorshift128plus(void) {
uint64_t x = shift128plus_s[0];
uint64_t const y = shift128plus_s[1];
shift128plus_s[0] = y;
x ^= x << 23; // a
x ^= x >> 17; // b
x ^= y ^ (y >> 26); // c
shift128plus_s[1] = x;
return x + y;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2014, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PROTOCOL_H
#define PROTOCOL_H
typedef struct protocol {
const int default_port;
int(*const parse_packet)(const char *, size_t, char **);
} protocol_t;
#endif

View File

@ -0,0 +1,444 @@
/*
* Copyright (c) 2014, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ev.h>
#include <udns.h>
#ifdef __MINGW32__
#include "win32.h"
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#endif
#include "resolv.h"
#include "utils.h"
#include "netutils.h"
/*
* Implement DNS resolution interface using libudns
*/
struct ResolvQuery {
void (*client_cb)(struct sockaddr *, void *);
void (*client_free_cb)(void *);
void *client_cb_data;
struct dns_query *queries[2];
size_t response_count;
struct sockaddr **responses;
uint16_t port;
};
extern int verbose;
static struct ev_io resolv_io_watcher;
static struct ev_timer resolv_timeout_watcher;
static const int MODE_IPV4_ONLY = 0;
static const int MODE_IPV6_ONLY = 1;
static const int MODE_IPV4_FIRST = 2;
static const int MODE_IPV6_FIRST = 3;
static int resolv_mode = 0;
static void resolv_sock_cb(struct ev_loop *, struct ev_io *, int);
static void resolv_timeout_cb(struct ev_loop *, struct ev_timer *, int);
static void dns_query_v4_cb(struct dns_ctx *, struct dns_rr_a4 *, void *);
static void dns_query_v6_cb(struct dns_ctx *, struct dns_rr_a6 *, void *);
static void dns_timer_setup_cb(struct dns_ctx *, int, void *);
static void process_client_callback(struct ResolvQuery *);
static inline int all_queries_are_null(struct ResolvQuery *);
static struct sockaddr *choose_ipv4_first(struct ResolvQuery *);
static struct sockaddr *choose_ipv6_first(struct ResolvQuery *);
static struct sockaddr *choose_any(struct ResolvQuery *);
int
resolv_init(struct ev_loop *loop, char **nameservers, int nameserver_num, int ipv6first)
{
if (ipv6first)
resolv_mode = MODE_IPV6_FIRST;
else
resolv_mode = MODE_IPV4_FIRST;
struct dns_ctx *ctx = &dns_defctx;
if (nameservers == NULL) {
/* Nameservers not specified, use system resolver config */
dns_init(ctx, 0);
} else {
dns_reset(ctx);
for (int i = 0; i < nameserver_num; i++) {
char *server = nameservers[i];
dns_add_serv(ctx, server);
}
}
int sockfd = dns_open(ctx);
if (sockfd < 0) {
FATAL("Failed to open DNS resolver socket");
}
if (nameserver_num == 1 && nameservers != NULL) {
if (strncmp("127.0.0.1", nameservers[0], 9) == 0
|| strncmp("::1", nameservers[0], 3) == 0) {
if (verbose) {
LOGI("bind UDP resolver to %s", nameservers[0]);
}
if (bind_to_address(sockfd, nameservers[0]) == -1)
ERROR("bind_to_address");
}
}
#ifdef __MINGW32__
setnonblocking(sockfd);
#else
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
#endif
ev_io_init(&resolv_io_watcher, resolv_sock_cb, sockfd, EV_READ);
resolv_io_watcher.data = ctx;
ev_io_start(loop, &resolv_io_watcher);
ev_timer_init(&resolv_timeout_watcher, resolv_timeout_cb, 0.0, 0.0);
resolv_timeout_watcher.data = ctx;
dns_set_tmcbck(ctx, dns_timer_setup_cb, loop);
return sockfd;
}
void
resolv_shutdown(struct ev_loop *loop)
{
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
ev_io_stop(loop, &resolv_io_watcher);
if (ev_is_active(&resolv_timeout_watcher)) {
ev_timer_stop(loop, &resolv_timeout_watcher);
}
dns_close(ctx);
}
struct ResolvQuery *
resolv_query(const char *hostname, void (*client_cb)(struct sockaddr *, void *),
void (*client_free_cb)(void *), void *client_cb_data,
uint16_t port)
{
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
/*
* Wrap udns's call back in our own
*/
struct ResolvQuery *cb_data = ss_malloc(sizeof(struct ResolvQuery));
if (cb_data == NULL) {
LOGE("Failed to allocate memory for DNS query callback data.");
return NULL;
}
memset(cb_data, 0, sizeof(struct ResolvQuery));
cb_data->client_cb = client_cb;
cb_data->client_free_cb = client_free_cb;
cb_data->client_cb_data = client_cb_data;
memset(cb_data->queries, 0, sizeof(cb_data->queries));
cb_data->response_count = 0;
cb_data->responses = NULL;
cb_data->port = port;
/* Submit A and AAAA queries */
if (resolv_mode != MODE_IPV6_ONLY) {
cb_data->queries[0] = dns_submit_a4(ctx,
hostname, 0,
dns_query_v4_cb, cb_data);
if (cb_data->queries[0] == NULL) {
LOGE("Failed to submit DNS query: %s",
dns_strerror(dns_status(ctx)));
}
}
if (resolv_mode != MODE_IPV4_ONLY) {
cb_data->queries[1] = dns_submit_a6(ctx,
hostname, 0,
dns_query_v6_cb, cb_data);
if (cb_data->queries[1] == NULL) {
LOGE("Failed to submit DNS query: %s",
dns_strerror(dns_status(ctx)));
}
}
if (all_queries_are_null(cb_data)) {
if (cb_data->client_free_cb != NULL) {
cb_data->client_free_cb(cb_data->client_cb_data);
}
ss_free(cb_data);
}
return cb_data;
}
void
resolv_cancel(struct ResolvQuery *query_handle)
{
struct ResolvQuery *cb_data = (struct ResolvQuery *)query_handle;
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
for (int i = 0; i < sizeof(cb_data->queries) / sizeof(cb_data->queries[0]);
i++)
if (cb_data->queries[i] != NULL) {
dns_cancel(ctx, cb_data->queries[i]);
ss_free(cb_data->queries[i]);
}
if (cb_data->client_free_cb != NULL) {
cb_data->client_free_cb(cb_data->client_cb_data);
}
ss_free(cb_data);
}
/*
* DNS UDP socket activity callback
*/
static void
resolv_sock_cb(struct ev_loop *loop, struct ev_io *w, int revents)
{
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
if (revents & EV_READ) {
dns_ioevent(ctx, ev_now(loop));
}
}
/*
* Wrapper for client callback we provide to udns
*/
static void
dns_query_v4_cb(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data)
{
struct ResolvQuery *cb_data = (struct ResolvQuery *)data;
if (result == NULL) {
if (verbose) {
LOGI("IPv4 resolv: %s", dns_strerror(dns_status(ctx)));
}
} else if (result->dnsa4_nrr > 0) {
struct sockaddr **new_responses = ss_realloc(cb_data->responses,
(cb_data->response_count +
result->dnsa4_nrr) *
sizeof(struct sockaddr *));
if (new_responses == NULL) {
LOGE("Failed to allocate memory for additional DNS responses");
} else {
cb_data->responses = new_responses;
for (int i = 0; i < result->dnsa4_nrr; i++) {
struct sockaddr_in *sa =
(struct sockaddr_in *)ss_malloc(sizeof(struct sockaddr_in));
sa->sin_family = AF_INET;
sa->sin_port = cb_data->port;
sa->sin_addr = result->dnsa4_addr[i];
cb_data->responses[cb_data->response_count] =
(struct sockaddr *)sa;
if (cb_data->responses[cb_data->response_count] == NULL) {
LOGE(
"Failed to allocate memory for DNS query result address");
} else {
cb_data->response_count++;
}
}
}
}
ss_free(result);
cb_data->queries[0] = NULL; /* mark A query as being completed */
/* Once all queries have completed, call client callback */
if (all_queries_are_null(cb_data)) {
return process_client_callback(cb_data);
}
}
static void
dns_query_v6_cb(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data)
{
struct ResolvQuery *cb_data = (struct ResolvQuery *)data;
if (result == NULL) {
if (verbose) {
LOGI("IPv6 resolv: %s", dns_strerror(dns_status(ctx)));
}
} else if (result->dnsa6_nrr > 0) {
struct sockaddr **new_responses = ss_realloc(cb_data->responses,
(cb_data->response_count +
result->dnsa6_nrr) *
sizeof(struct sockaddr *));
if (new_responses == NULL) {
LOGE("Failed to allocate memory for additional DNS responses");
} else {
cb_data->responses = new_responses;
for (int i = 0; i < result->dnsa6_nrr; i++) {
struct sockaddr_in6 *sa =
(struct sockaddr_in6 *)ss_malloc(sizeof(struct sockaddr_in6));
sa->sin6_family = AF_INET6;
sa->sin6_port = cb_data->port;
sa->sin6_addr = result->dnsa6_addr[i];
cb_data->responses[cb_data->response_count] =
(struct sockaddr *)sa;
if (cb_data->responses[cb_data->response_count] == NULL) {
LOGE(
"Failed to allocate memory for DNS query result address");
} else {
cb_data->response_count++;
}
}
}
}
ss_free(result);
cb_data->queries[1] = NULL; /* mark AAAA query as being completed */
/* Once all queries have completed, call client callback */
if (all_queries_are_null(cb_data)) {
return process_client_callback(cb_data);
}
}
/*
* Called once all queries have been completed
*/
static void
process_client_callback(struct ResolvQuery *cb_data)
{
struct sockaddr *best_address = NULL;
if (resolv_mode == MODE_IPV4_FIRST) {
best_address = choose_ipv4_first(cb_data);
} else if (resolv_mode == MODE_IPV6_FIRST) {
best_address = choose_ipv6_first(cb_data);
} else {
best_address = choose_any(cb_data);
}
cb_data->client_cb(best_address, cb_data->client_cb_data);
for (int i = 0; i < cb_data->response_count; i++)
ss_free(cb_data->responses[i]);
ss_free(cb_data->responses);
if (cb_data->client_free_cb != NULL) {
cb_data->client_free_cb(cb_data->client_cb_data);
}
ss_free(cb_data);
}
static struct sockaddr *
choose_ipv4_first(struct ResolvQuery *cb_data)
{
for (int i = 0; i < cb_data->response_count; i++)
if (cb_data->responses[i]->sa_family == AF_INET) {
return cb_data->responses[i];
}
return choose_any(cb_data);
}
static struct sockaddr *
choose_ipv6_first(struct ResolvQuery *cb_data)
{
for (int i = 0; i < cb_data->response_count; i++)
if (cb_data->responses[i]->sa_family == AF_INET6) {
return cb_data->responses[i];
}
return choose_any(cb_data);
}
static struct sockaddr *
choose_any(struct ResolvQuery *cb_data)
{
if (cb_data->response_count >= 1) {
return cb_data->responses[0];
}
return NULL;
}
/*
* DNS timeout callback
*/
static void
resolv_timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
if (revents & EV_TIMER) {
dns_timeouts(ctx, 30, ev_now(loop));
}
}
/*
* Callback to setup DNS timeout callback
*/
static void
dns_timer_setup_cb(struct dns_ctx *ctx, int timeout, void *data)
{
struct ev_loop *loop = (struct ev_loop *)data;
if (ev_is_active(&resolv_timeout_watcher)) {
ev_timer_stop(loop, &resolv_timeout_watcher);
}
if (ctx != NULL && timeout >= 0) {
ev_timer_set(&resolv_timeout_watcher, timeout, 0.0);
ev_timer_start(loop, &resolv_timeout_watcher);
}
}
static inline int
all_queries_are_null(struct ResolvQuery *cb_data)
{
int result = 1;
for (int i = 0; i < sizeof(cb_data->queries) / sizeof(cb_data->queries[0]);
i++)
result = result && cb_data->queries[i] == NULL;
return result;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2014, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RESOLV_H
#define RESOLV_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdint.h>
#ifdef __MINGW32__
#include "win32.h"
#else
#include <sys/socket.h>
#endif
struct ResolvQuery;
int resolv_init(struct ev_loop *, char **, int, int);
struct ResolvQuery *resolv_query(const char *, void (*)(struct sockaddr *,
void *), void (*)(
void *), void *, uint16_t);
void resolv_cancel(struct ResolvQuery *);
void resolv_shutdown(struct ev_loop *);
#endif

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* Copyright (c) 2011 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#ifdef __MINGW32__
extern void ss_error(const char *s);
#endif
#include "rule.h"
#include "utils.h"
static void free_rule(rule_t *);
rule_t *
new_rule()
{
rule_t *rule;
rule = calloc(1, sizeof(rule_t));
if (rule == NULL) {
ERROR("malloc");
return NULL;
}
return rule;
}
int
accept_rule_arg(rule_t *rule, const char *arg)
{
if (rule->pattern == NULL) {
rule->pattern = strdup(arg);
if (rule->pattern == NULL) {
ERROR("strdup failed");
return -1;
}
} else {
LOGE("Unexpected table rule argument: %s", arg);
return -1;
}
return 1;
}
void
add_rule(struct cork_dllist *rules, rule_t *rule)
{
cork_dllist_add(rules, &rule->entries);
}
int
init_rule(rule_t *rule)
{
if (rule->pattern_re == NULL) {
const char *reerr;
int reerroffset;
rule->pattern_re =
pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL);
if (rule->pattern_re == NULL) {
LOGE("Regex compilation of \"%s\" failed: %s, offset %d",
rule->pattern, reerr, reerroffset);
return 0;
}
}
return 1;
}
rule_t *
lookup_rule(const struct cork_dllist *rules, const char *name, size_t name_len)
{
struct cork_dllist_item *curr, *next;
if (name == NULL) {
name = "";
name_len = 0;
}
cork_dllist_foreach_void(rules, curr, next) {
rule_t *rule = cork_container_of(curr, rule_t, entries);
if (pcre_exec(rule->pattern_re, NULL,
name, name_len, 0, 0, NULL, 0) >= 0)
return rule;
}
return NULL;
}
void
remove_rule(rule_t *rule)
{
cork_dllist_remove(&rule->entries);
free_rule(rule);
}
static void
free_rule(rule_t *rule)
{
if (rule == NULL)
return;
ss_free(rule->pattern);
if (rule->pattern_re != NULL)
pcre_free(rule->pattern_re);
ss_free(rule);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* Copyright (c) 2011 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef RULE_H
#define RULE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <libcork/ds.h>
#ifdef HAVE_PCRE_H
#include <pcre.h>
#elif HAVE_PCRE_PCRE_H
#include <pcre/pcre.h>
#endif
typedef struct rule {
char *pattern;
/* Runtime fields */
pcre *pattern_re;
struct cork_dllist_item entries;
} rule_t;
void add_rule(struct cork_dllist *, rule_t *);
int init_rule(rule_t *);
rule_t *lookup_rule(const struct cork_dllist *, const char *, size_t);
void remove_rule(rule_t *);
rule_t *new_rule();
int accept_rule_arg(rule_t *, const char *);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
/*
* server.h - Define shadowsocks server's buffers and callbacks
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _SERVER_H
#define _SERVER_H
#include <ev.h>
#include <time.h>
#include <libcork/ds.h>
#include "encrypt.h"
#include "jconf.h"
#include "resolv.h"
#include "obfs.h"
#include "protocol.h"
#include "common.h"
typedef struct listen_ctx {
ev_io io;
int fd;
int timeout;
int method;
char *iface;
struct ev_loop *loop;
// SSR
char *protocol_name;
char *protocol_param;
char *obfs_name;
char *obfs_param;
void **list_protocol_global;
void **list_obfs_global;
} listen_ctx_t;
typedef struct server_ctx {
ev_io io;
ev_timer watcher;
int connected;
struct server *server;
} server_ctx_t;
typedef struct server {
int fd;
int stage;
buffer_t *buf;
ssize_t buf_capacity;
buffer_t *header_buf;
int auth;
struct chunk *chunk;
struct enc_ctx *e_ctx;
struct enc_ctx *d_ctx;
struct server_ctx *recv_ctx;
struct server_ctx *send_ctx;
struct listen_ctx *listen_ctx;
struct remote *remote;
struct ResolvQuery *query;
struct cork_dllist_item entries;
// SSR
obfs *protocol;
obfs *obfs;
obfs_class *protocol_plugin;
obfs_class *obfs_plugin;
int obfs_compatible_state;
int protocol_compatible_state;
} server_t;
typedef struct query {
server_t *server;
char hostname[257];
} query_t;
typedef struct remote_ctx {
ev_io io;
int connected;
struct remote *remote;
} remote_ctx_t;
typedef struct remote {
int fd;
buffer_t *buf;
ssize_t buf_capacity;
struct remote_ctx *recv_ctx;
struct remote_ctx *send_ctx;
struct server *server;
// SSR
int remote_index;
} remote_t;
#endif // _SERVER_H

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is a minimal TLS implementation intended only to parse the server name
* extension. This was created based primarily on Wireshark dissection of a
* TLS handshake and RFC4366.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h> /* malloc() */
#include <string.h> /* strncpy() */
#ifndef __MINGW32__
#include <sys/socket.h>
#else
#include <win32.h>
#endif
#include "tls.h"
#include "protocol.h"
#include "utils.h"
#define SERVER_NAME_LEN 256
#define TLS_HEADER_LEN 5
#define TLS_HANDSHAKE_CONTENT_TYPE 0x16
#define TLS_HANDSHAKE_TYPE_CLIENT_HELLO 0x01
#ifndef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
extern int verbose;
static int parse_tls_header(const char *, size_t, char **);
static int parse_extensions(const char *, size_t, char **);
static int parse_server_name_extension(const char *, size_t, char **);
static const protocol_t tls_protocol_st = {
.default_port = 443,
.parse_packet = &parse_tls_header,
};
const protocol_t *const tls_protocol = &tls_protocol_st;
/* Parse a TLS packet for the Server Name Indication extension in the client
* hello handshake, returning the first servername found (pointer to static
* array)
*
* Returns:
* >=0 - length of the hostname and updates *hostname
* caller is responsible for freeing *hostname
* -1 - Incomplete request
* -2 - No Host header included in this request
* -3 - Invalid hostname pointer
* -4 - malloc failure
* < -4 - Invalid TLS client hello
*/
static int
parse_tls_header(const char *data, size_t data_len, char **hostname)
{
char tls_content_type;
char tls_version_major;
char tls_version_minor;
size_t pos = TLS_HEADER_LEN;
size_t len;
if (hostname == NULL)
return -3;
/* Check that our TCP payload is at least large enough for a TLS header */
if (data_len < TLS_HEADER_LEN)
return -1;
/* SSL 2.0 compatible Client Hello
*
* High bit of first byte (length) and content type is Client Hello
*
* See RFC5246 Appendix E.2
*/
if (data[0] & 0x80 && data[2] == 1) {
if (verbose)
LOGI("Received SSL 2.0 Client Hello which can not support SNI.");
return -2;
}
tls_content_type = data[0];
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
if (verbose)
LOGI("Request did not begin with TLS handshake.");
return -5;
}
tls_version_major = data[1];
tls_version_minor = data[2];
if (tls_version_major < 3) {
if (verbose)
LOGI("Received SSL %d.%d handshake which can not support SNI.",
tls_version_major, tls_version_minor);
return -2;
}
/* TLS record length */
len = ((unsigned char)data[3] << 8) +
(unsigned char)data[4] + TLS_HEADER_LEN;
data_len = MIN(data_len, len);
/* Check we received entire TLS record length */
if (data_len < len)
return -1;
/*
* Handshake
*/
if (pos + 1 > data_len) {
return -5;
}
if (data[pos] != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
if (verbose)
LOGI("Not a client hello");
return -5;
}
/* Skip past fixed length records:
* 1 Handshake Type
* 3 Length
* 2 Version (again)
* 32 Random
* to Session ID Length
*/
pos += 38;
/* Session ID */
if (pos + 1 > data_len)
return -5;
len = (unsigned char)data[pos];
pos += 1 + len;
/* Cipher Suites */
if (pos + 2 > data_len)
return -5;
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
pos += 2 + len;
/* Compression Methods */
if (pos + 1 > data_len)
return -5;
len = (unsigned char)data[pos];
pos += 1 + len;
if (pos == data_len && tls_version_major == 3 && tls_version_minor == 0) {
if (verbose)
LOGI("Received SSL 3.0 handshake without extensions");
return -2;
}
/* Extensions */
if (pos + 2 > data_len)
return -5;
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
pos += 2;
if (pos + len > data_len)
return -5;
return parse_extensions(data + pos, len, hostname);
}
static int
parse_extensions(const char *data, size_t data_len, char **hostname)
{
size_t pos = 0;
size_t len;
/* Parse each 4 bytes for the extension header */
while (pos + 4 <= data_len) {
/* Extension Length */
len = ((unsigned char)data[pos + 2] << 8) +
(unsigned char)data[pos + 3];
/* Check if it's a server name extension */
if (data[pos] == 0x00 && data[pos + 1] == 0x00) {
/* There can be only one extension of each type, so we break
* our state and move p to beinnging of the extension here */
if (pos + 4 + len > data_len)
return -5;
return parse_server_name_extension(data + pos + 4, len, hostname);
}
pos += 4 + len; /* Advance to the next extension header */
}
/* Check we ended where we expected to */
if (pos != data_len)
return -5;
return -2;
}
static int
parse_server_name_extension(const char *data, size_t data_len,
char **hostname)
{
size_t pos = 2; /* skip server name list length */
size_t len;
while (pos + 3 < data_len) {
len = ((unsigned char)data[pos + 1] << 8) +
(unsigned char)data[pos + 2];
if (pos + 3 + len > data_len)
return -5;
switch (data[pos]) { /* name type */
case 0x00: /* host_name */
*hostname = malloc(len + 1);
if (*hostname == NULL) {
ERROR("malloc() failure");
return -4;
}
strncpy(*hostname, data + pos + 3, len);
(*hostname)[len] = '\0';
return len;
default:
if (verbose)
LOGI("Unknown server name extension name type: %d",
data[pos]);
}
pos += 3 + len;
}
/* Check we ended where we expected to */
if (pos != data_len)
return -5;
return -2;
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TLS_H
#define TLS_H
#include "protocol.h"
const protocol_t *const tls_protocol;
#endif

View File

@ -0,0 +1,609 @@
#include "tls1.2_ticket.h"
#include "list.c"
typedef struct tls12_ticket_auth_global_data {
uint8_t local_client_id[32];
List client_data;
time_t startup_time;
}tls12_ticket_auth_global_data;
typedef struct tls12_ticket_auth_local_data {
int handshake_status;
char *send_buffer;
int send_buffer_size;
char *recv_buffer;
int recv_buffer_size;
}tls12_ticket_auth_local_data;
void tls12_ticket_auth_local_data_init(tls12_ticket_auth_local_data* local) {
local->handshake_status = 0;
local->send_buffer = malloc(0);
local->send_buffer_size = 0;
local->recv_buffer = malloc(0);
local->recv_buffer_size = 0;
}
void * tls12_ticket_auth_init_data() {
tls12_ticket_auth_global_data *global = (tls12_ticket_auth_global_data*)malloc(sizeof(tls12_ticket_auth_global_data));
rand_bytes(global->local_client_id, 32);
global->client_data = list_init(22);
global->startup_time = time(NULL);
return global;
}
obfs * tls12_ticket_auth_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(tls12_ticket_auth_local_data));
tls12_ticket_auth_local_data_init((tls12_ticket_auth_local_data*)self->l_data);
return self;
}
void tls12_ticket_auth_dispose(obfs *self) {
tls12_ticket_auth_local_data *local = (tls12_ticket_auth_local_data*)self->l_data;
if (local->send_buffer != NULL) {
free(local->send_buffer);
local->send_buffer = NULL;
}
if (local->recv_buffer != NULL) {
free(local->recv_buffer);
local->recv_buffer = NULL;
}
free(local);
dispose_obfs(self);
}
int tls12_ticket_pack_auth_data(tls12_ticket_auth_global_data *global, server_info *server, char *outdata) {
int out_size = 32;
time_t t = time(NULL);
outdata[0] = t >> 24;
outdata[1] = t >> 16;
outdata[2] = t >> 8;
outdata[3] = t;
rand_bytes((uint8_t*)outdata + 4, 18);
uint8_t *key = (uint8_t*)malloc(server->key_len + 32);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, server->key, server->key_len);
memcpy(key + server->key_len, global->local_client_id, 32);
ss_sha1_hmac_with_key(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, key, server->key_len + 32);
free(key);
memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN);
return out_size;
}
void tls12_ticket_auth_pack_data(char *encryptdata, int datalength, int start, int len, char *out_buffer, int outlength) {
out_buffer[outlength] = 0x17;
out_buffer[outlength + 1] = 0x3;
out_buffer[outlength + 2] = 0x3;
out_buffer[outlength + 3] = len >> 8;
out_buffer[outlength + 4] = len;
memcpy(out_buffer + outlength + 5, encryptdata + start, len);
}
int tls12_ticket_auth_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
tls12_ticket_auth_local_data *local = (tls12_ticket_auth_local_data*)self->l_data;
tls12_ticket_auth_global_data *global = (tls12_ticket_auth_global_data*)self->server.g_data;
char * out_buffer = NULL;
if (local->handshake_status == 8) {
if (datalength < 1024) {
if (*capacity < datalength + 5) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = (datalength + 5) * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata + 5, encryptdata, datalength);
encryptdata[0] = 0x17;
encryptdata[1] = 0x3;
encryptdata[2] = 0x3;
encryptdata[3] = datalength >> 8;
encryptdata[4] = datalength;
return datalength + 5;
} else {
out_buffer = (char*)malloc(datalength + 2048);
int start = 0;
int outlength = 0;
int len;
while (datalength - start > 2048) {
len = xorshift128plus() % 4096 + 100;
if (len > datalength - start)
len = datalength - start;
tls12_ticket_auth_pack_data(encryptdata, datalength, start, len, out_buffer, outlength);
outlength += len + 5;
start += len;
}
if (datalength - start > 0) {
len = datalength - start;
tls12_ticket_auth_pack_data(encryptdata, datalength, start, len, out_buffer, outlength);
outlength += len + 5;
}
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, out_buffer, outlength);
free(out_buffer);
return outlength;
}
}
local->send_buffer = (char*)realloc(local->send_buffer, local->send_buffer_size + datalength + 5);
memcpy(local->send_buffer + local->send_buffer_size + 5, encryptdata, datalength);
local->send_buffer[local->send_buffer_size] = 0x17;
local->send_buffer[local->send_buffer_size + 1] = 0x3;
local->send_buffer[local->send_buffer_size + 2] = 0x3;
local->send_buffer[local->send_buffer_size + 3] = datalength >> 8;
local->send_buffer[local->send_buffer_size + 4] = datalength;
local->send_buffer_size += datalength + 5;
if (local->handshake_status == 0) {
#define CSTR_DECL(name, len, str) const char* name = str; const int len = sizeof(str) - 1;
CSTR_DECL(tls_data0, tls_data0_len, "\x00\x1c\xc0\x2b\xc0\x2f\xcc\xa9\xcc\xa8\xcc\x14\xcc\x13\xc0\x0a\xc0\x14\xc0\x09\xc0\x13\x00\x9c\x00\x35\x00\x2f\x00\x0a\x01\x00"
);
CSTR_DECL(tls_data1, tls_data1_len, "\xff\x01\x00\x01\x00"
);
CSTR_DECL(tls_data2, tls_data2_len, "\x00\x17\x00\x00\x00\x23\x00\xd0");
CSTR_DECL(tls_data3, tls_data3_len, "\x00\x0d\x00\x16\x00\x14\x06\x01\x06\x03\x05\x01\x05\x03\x04\x01\x04\x03\x03\x01\x03\x03\x02\x01\x02\x03\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x12\x00\x00\x75\x50\x00\x00\x00\x0b\x00\x02\x01\x00\x00\x0a\x00\x06\x00\x04\x00\x17\x00\x18"
//"00150066000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // padding
);
uint8_t tls_data[2048];
int tls_data_len = 0;
memcpy(tls_data, tls_data1, tls_data1_len);
tls_data_len += tls_data1_len;
char hosts[1024];
char * phost[128];
int host_num = 0;
int pos;
char sni[256] = {0};
if (self->server.param && strlen(self->server.param) == 0)
self->server.param = NULL;
strncpy(hosts, self->server.param ? self->server.param : self->server.host, sizeof hosts);
phost[host_num++] = hosts;
for (pos = 0; hosts[pos]; ++pos) {
if (hosts[pos] == ',') {
phost[host_num++] = &hosts[pos + 1];
}
}
host_num = xorshift128plus() % host_num;
sprintf(sni, "%s", phost[host_num]);
int sni_len = strlen(sni);
if (sni_len > 0 && sni[sni_len - 1] >= '0' && sni[sni_len - 1] <= '9')
sni_len = 0;
tls_data[tls_data_len] = '\0';
tls_data[tls_data_len + 1] = '\0';
tls_data[tls_data_len + 2] = (sni_len + 5) >> 8;
tls_data[tls_data_len + 3] = (sni_len + 5);
tls_data[tls_data_len + 4] = (sni_len + 3) >> 8;
tls_data[tls_data_len + 5] = (sni_len + 3);
tls_data[tls_data_len + 6] = '\0';
tls_data[tls_data_len + 7] = sni_len >> 8;
tls_data[tls_data_len + 8] = sni_len;
memcpy(tls_data + tls_data_len + 9, sni, sni_len);
tls_data_len += 9 + sni_len;
memcpy(tls_data + tls_data_len, tls_data2, tls_data2_len);
tls_data_len += tls_data2_len;
rand_bytes(tls_data + tls_data_len, 208);
tls_data_len += 208;
memcpy(tls_data + tls_data_len, tls_data3, tls_data3_len);
tls_data_len += tls_data3_len;
datalength = 11 + 32 + 1 + 32 + tls_data0_len + 2 + tls_data_len;
out_buffer = (char*)malloc(datalength);
char *pdata = out_buffer + datalength - tls_data_len;
int len = tls_data_len;
memcpy(pdata, tls_data, tls_data_len);
pdata[-1] = tls_data_len;
pdata[-2] = tls_data_len >> 8;
pdata -= 2; len += 2;
memcpy(pdata - tls_data0_len, tls_data0, tls_data0_len);
pdata -= tls_data0_len; len += tls_data0_len;
memcpy(pdata - 32, global->local_client_id, 32);
pdata -= 32; len += 32;
pdata[-1] = 0x20;
pdata -= 1; len += 1;
tls12_ticket_pack_auth_data(global, &self->server, pdata - 32);
pdata -= 32; len += 32;
pdata[-1] = 0x3;
pdata[-2] = 0x3; // tls version
pdata -= 2; len += 2;
pdata[-1] = len;
pdata[-2] = len >> 8;
pdata[-3] = 0;
pdata[-4] = 1;
pdata -= 4; len += 4;
pdata[-1] = len;
pdata[-2] = len >> 8;
pdata -= 2; len += 2;
pdata[-1] = 0x1;
pdata[-2] = 0x3; // tls version
pdata -= 2; len += 2;
pdata[-1] = 0x16; // tls handshake
pdata -= 1; len += 1;
local->handshake_status = 1;
} else if (datalength == 0) {
datalength = local->send_buffer_size + 43;
out_buffer = (char*)malloc(datalength);
char *pdata = out_buffer;
memcpy(pdata, "\x14\x03\x03\x00\x01\x01", 6);
pdata += 6;
memcpy(pdata, "\x16\x03\x03\x00\x20", 5);
pdata += 5;
rand_bytes((uint8_t*)pdata, 22);
pdata += 22;
uint8_t *key = (uint8_t*)malloc(self->server.key_len + 32);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, self->server.key, self->server.key_len);
memcpy(key + self->server.key_len, global->local_client_id, 32);
ss_sha1_hmac_with_key(hash, out_buffer, pdata - out_buffer, key, self->server.key_len + 32);
free(key);
memcpy(pdata, hash, OBFS_HMAC_SHA1_LEN);
pdata += OBFS_HMAC_SHA1_LEN;
memcpy(pdata, local->send_buffer, local->send_buffer_size);
free(local->send_buffer);
local->send_buffer = NULL;
local->handshake_status = 8;
} else {
return 0;
}
if (*capacity < datalength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = datalength * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata, out_buffer, datalength);
free(out_buffer);
return datalength;
}
int tls12_ticket_auth_server_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity) {
char *encryptdata = *pencryptdata;
tls12_ticket_auth_local_data *local = (tls12_ticket_auth_local_data*)self->l_data;
tls12_ticket_auth_global_data *global = (tls12_ticket_auth_global_data*)self->server.g_data;
char * out_buffer = NULL;
if (local->handshake_status == 8) {
if (datalength < 1024) {
if (*capacity < datalength + 5) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = (datalength + 5) * 2);
encryptdata = *pencryptdata;
}
memmove(encryptdata + 5, encryptdata, datalength);
encryptdata[0] = 0x17;
encryptdata[1] = 0x3;
encryptdata[2] = 0x3;
encryptdata[3] = datalength >> 8;
encryptdata[4] = datalength;
return datalength + 5;
} else {
out_buffer = (char*)malloc(datalength + 2048);
int start = 0;
int outlength = 0;
int len;
while (datalength - start > 2048) {
len = xorshift128plus() % 4096 + 100;
if (len > datalength - start)
len = datalength - start;
tls12_ticket_auth_pack_data(encryptdata, datalength, start, len, out_buffer, outlength);
outlength += len + 5;
start += len;
}
if (datalength - start > 0) {
len = datalength - start;
tls12_ticket_auth_pack_data(encryptdata, datalength, start, len, out_buffer, outlength);
outlength += len + 5;
}
if (*capacity < outlength) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = outlength * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata, out_buffer, outlength);
free(out_buffer);
return outlength;
}
}
local->handshake_status = 3;
out_buffer = (char*)malloc(43 + 86);
int data_len = 0;
char *p_data = out_buffer + 86;
memcpy(p_data - 10, "\xc0\x2f\x00\x00\x05\xff\x01\x00\x01\x00", 10);
p_data -= 10;data_len += 10;
memcpy(p_data - 32, global->local_client_id, 32);
p_data -= 32;data_len += 32;
p_data[-1] = 0x20;
p_data -= 1;data_len += 1;
tls12_ticket_pack_auth_data(global, &self->server, p_data - 32);
p_data -= 32;data_len += 32;
p_data[-1] = 0x3;
p_data[-2] = 0x3; // tls version
p_data -= 2;data_len += 2;
p_data[-1] = data_len;
p_data[-2] = data_len >> 8;
p_data[-3] = 0x00;
p_data[-4] = 0x02;
p_data -= 4; data_len += 4;
p_data[-1] = data_len;
p_data[-2] = data_len >> 8;
p_data[-3] = 0x03;
p_data[-4] = 0x03;
p_data[-5] = 0x16;
p_data -= 5; data_len += 5;
memcpy(out_buffer, p_data, data_len);
char *pdata = out_buffer + 86;
memcpy(pdata, "\x14\x03\x03\x00\x01\x01", 6);
pdata += 6;
memcpy(pdata, "\x16\x03\x03\x00\x20", 5);
pdata += 5;
rand_bytes((uint8_t*)pdata, 22);
pdata += 22;
uint8_t *key = (uint8_t*)malloc(self->server.key_len + 32);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, self->server.key, self->server.key_len);
memcpy(key + self->server.key_len, global->local_client_id, 32);
ss_sha1_hmac_with_key(hash, out_buffer, 43 + 86, key, self->server.key_len + 32);
free(key);
memcpy(pdata, hash, OBFS_HMAC_SHA1_LEN);
memmove(encryptdata, out_buffer, 43 + 86);
free(out_buffer);
return 43 + 86;
}
int tls12_ticket_auth_client_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
tls12_ticket_auth_local_data *local = (tls12_ticket_auth_local_data*)self->l_data;
tls12_ticket_auth_global_data *global = (tls12_ticket_auth_global_data*)self->server.g_data;
*needsendback = 0;
if (local->handshake_status == 8) {
local->recv_buffer_size += datalength;
local->recv_buffer = (char*)realloc(local->recv_buffer, local->recv_buffer_size);
memcpy(local->recv_buffer + local->recv_buffer_size - datalength, encryptdata, datalength);
datalength = 0;
while (local->recv_buffer_size > 5) {
if (local->recv_buffer[0] != 0x17)
return -1;
int size = ((int)(unsigned char)local->recv_buffer[3] << 8) + (unsigned char)local->recv_buffer[4];
if (size + 5 > local->recv_buffer_size)
break;
if (*capacity < datalength + size) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = (datalength + size) * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata + datalength, local->recv_buffer + 5, size);
datalength += size;
local->recv_buffer_size -= 5 + size;
memmove(local->recv_buffer, local->recv_buffer + 5 + size, local->recv_buffer_size);
}
return datalength;
}
if (datalength < 11 + 32 + 1 + 32) {
return -1;
}
uint8_t *key = (uint8_t*)malloc(self->server.key_len + 32);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, self->server.key, self->server.key_len);
memcpy(key + self->server.key_len, global->local_client_id, 32);
ss_sha1_hmac_with_key(hash, encryptdata + 11, 22, key, self->server.key_len + 32);
free(key);
if (memcmp(encryptdata + 33, hash, OBFS_HMAC_SHA1_LEN)) {
return -1;
}
*needsendback = 1;
return 0;
}
int tls12_ticket_auth_server_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback) {
char *encryptdata = *pencryptdata;
tls12_ticket_auth_local_data *local = (tls12_ticket_auth_local_data*)self->l_data;
tls12_ticket_auth_global_data *global = (tls12_ticket_auth_global_data*)self->server.g_data;
*needsendback = 0;
if (local->handshake_status == 8) {
if(datalength != 0)
{
local->recv_buffer = (char*)realloc(local->recv_buffer, local->recv_buffer_size + datalength);
memmove(local->recv_buffer + local->recv_buffer_size, encryptdata, datalength);
local->recv_buffer_size += datalength;
}
datalength = 0;
while (local->recv_buffer_size > 5) {
if (local->recv_buffer[0] != 0x17 || local->recv_buffer[1] != 0x03 || local->recv_buffer[2] != 0x03)
{
LOGE("server_decode data error, wrong tls version 3");
return -1;
}
int size = ((int)(unsigned char)local->recv_buffer[3] << 8) + (unsigned char)local->recv_buffer[4];
if (size + 5 > local->recv_buffer_size)
break;
if (*capacity < local->recv_buffer_size + size) {
*pencryptdata = (char*)realloc(*pencryptdata, *capacity = (local->recv_buffer_size + size) * 2);
encryptdata = *pencryptdata;
}
memcpy(encryptdata + datalength, local->recv_buffer + 5, size);
datalength += size;
local->recv_buffer_size -= 5 + size;
memmove(local->recv_buffer, local->recv_buffer + 5 + size, local->recv_buffer_size);
}
return datalength;
}
if (local->handshake_status == 3) {
char *verify = encryptdata;
if(datalength < 43)
{
LOGE("server_decode data error, too short:%d", (int)datalength);
return -1;
}
if(encryptdata[0] != 0x14 || encryptdata[1] != 0x03 || encryptdata[2] != 0x03 || encryptdata[3] != 0x00 || encryptdata[4] != 0x01 || encryptdata[5] != 0x01)
{
LOGE("server_decode data error, wrong tls version");
return -1;
}
encryptdata += 6;
if(encryptdata[0] != 0x16 || encryptdata[1] != 0x03 || encryptdata[2] != 0x03 || encryptdata[3] != 0x00 || encryptdata[4] != 0x20)
{
LOGE("server_decode data error, wrong tls version 2");
return -1;
}
uint8_t *key = (uint8_t*)malloc(self->server.key_len + 32);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, self->server.key, self->server.key_len);
memcpy(key + self->server.key_len, global->local_client_id, 32);
ss_sha1_hmac_with_key(hash, verify, 33, key, self->server.key_len + 32);
free(key);
if (memcmp(verify + 33, hash, OBFS_HMAC_SHA1_LEN) != 0) {
LOGE("server_decode data error, hash Mismatch %d",(int)memcmp(verify + 33, hash, OBFS_HMAC_SHA1_LEN));
return -1;
}
local->recv_buffer_size = datalength - 43;
local->recv_buffer = (char*)realloc(local->recv_buffer, local->recv_buffer_size);
memmove(local->recv_buffer, encryptdata + 37, datalength - 43);
local->handshake_status = 8;
return tls12_ticket_auth_server_decode(self, pencryptdata, 0, capacity, needsendback);
}
local->handshake_status = 2;
if(encryptdata[0] != 0x16 || encryptdata[1] != 0x03 || encryptdata[2] != 0x01)
{
return -1;
}
encryptdata += 3;
{
int size = ((int)(unsigned char)encryptdata[0] << 8) + (unsigned char)encryptdata[1];
if(size != datalength - 5)
{
LOGE("tls_auth wrong tls head size");
return -1;
}
}
encryptdata += 2;
if(encryptdata[0] != 0x01 || encryptdata[1] != 0x00)
{
LOGE("tls_auth not client hello message");
return -1;
}
encryptdata += 2;
{
int size = ((int)(unsigned char)encryptdata[0] << 8) + (unsigned char)encryptdata[1];
if(size != datalength - 9)
{
LOGE("tls_auth wrong message size");
return -1;
}
}
encryptdata += 2;
if(encryptdata[0] != 0x03 || encryptdata[1] != 0x03)
{
LOGE("tls_auth wrong tls version");
return -1;
}
encryptdata += 2;
char *verifyid = encryptdata;
encryptdata += 32;
int sessionid_len = encryptdata[0];
if(sessionid_len < 32)
{
LOGE("tls_auth wrong sessionid_len");
return -1;
}
char *sessionid = encryptdata + 1;
memcpy(global->local_client_id , sessionid, sessionid_len);
uint8_t *key = (uint8_t*)malloc(self->server.key_len + sessionid_len);
char hash[ONETIMEAUTH_BYTES * 2];
memcpy(key, self->server.key, self->server.key_len);
memcpy(key + self->server.key_len, global->local_client_id, sessionid_len);
ss_sha1_hmac_with_key(hash, verifyid, 22, key, self->server.key_len + sessionid_len);
free(key);
encryptdata += (sessionid_len + 1);
long utc_time = ((int)(unsigned char)verifyid[0] << 24) + ((int)(unsigned char)verifyid[1] << 16) + ((int)(unsigned char)verifyid[2] << 8) + (unsigned char)verifyid[3];
time_t t = time(NULL);
if (self->server.param && strlen(self->server.param) == 0)
{
self->server.param = NULL;
}
int max_time_dif = 0;
int time_dif = utc_time - t;
if(self->server.param)
{
max_time_dif = atoi(self->server.param);
}
if(max_time_dif > 0 && (time_dif < -max_time_dif || time_dif > max_time_dif || utc_time - global->startup_time < -max_time_dif / 2))
{
LOGE("tls_auth wrong time");
return -1;
}
if (memcmp(verifyid + 22, hash, OBFS_HMAC_SHA1_LEN)) {
LOGE("tls_auth wrong sha1");
return -1;
}
int search_result = global->client_data->have_same_cmp(global->client_data, verifyid);
if(search_result != 0)
{
LOGE("replay attack detect!");
return -1;
}
global->client_data->add_back(global->client_data, verifyid);
encryptdata += 48;
*needsendback = 1;
return 0;
}

View File

@ -0,0 +1,20 @@
/*
* http_simple.h - Define shadowsocksR server's buffers and callbacks
*
* Copyright (C) 2015 - 2016, Break Wa11 <mmgac001@gmail.com>
*/
#ifndef _TLS1_2_TICKET_H
#define _TLS1_2_TICKET_H
void * tls12_ticket_auth_init_data();
obfs * tls12_ticket_auth_new_obfs();
void tls12_ticket_auth_dispose(obfs *self);
int tls12_ticket_auth_client_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity);
int tls12_ticket_auth_client_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback);
int tls12_ticket_auth_server_encode(obfs *self, char **pencryptdata, int datalength, size_t* capacity);
int tls12_ticket_auth_server_decode(obfs *self, char **pencryptdata, int datalength, size_t* capacity, int *needsendback);
#endif // _TLS1_2_TICKET_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/*
* udprelay.h - Define UDP relay's buffers and callbacks
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef _UDPRELAY_H
#define _UDPRELAY_H
#include <ev.h>
#include <time.h>
#include "encrypt.h"
#include "jconf.h"
#include "obfs.h"
#ifdef MODULE_REMOTE
#include "resolv.h"
#endif
#include "cache.h"
#include "common.h"
#define MAX_UDP_PACKET_SIZE (65507)
#define DEFAULT_PACKET_SIZE 1397 // 1492 - 1 - 28 - 2 - 64 = 1397, the default MTU for UDP relay
typedef struct server_ctx {
ev_io io;
int fd;
int method;
int auth;
int timeout;
const char *iface;
struct cache *conn_cache;
#ifdef MODULE_LOCAL
const struct sockaddr *remote_addr;
int remote_addr_len;
#ifdef MODULE_TUNNEL
ss_addr_t tunnel_addr;
#endif
#endif
#ifdef MODULE_REMOTE
struct ev_loop *loop;
#endif
// SSR
obfs *protocol;
obfs_class *protocol_plugin;
void *protocol_global;
} server_ctx_t;
#ifdef MODULE_REMOTE
typedef struct query_ctx {
struct ResolvQuery *query;
struct sockaddr_storage src_addr;
buffer_t *buf;
int addr_header_len;
char addr_header[384];
struct server_ctx *server_ctx;
struct remote_ctx *remote_ctx;
} query_ctx_t;
#endif
typedef struct remote_ctx {
ev_io io;
ev_timer watcher;
int af;
int fd;
int addr_header_len;
char addr_header[384];
struct sockaddr_storage src_addr;
#ifdef MODULE_REMOTE
struct sockaddr_storage dst_addr;
#endif
struct server_ctx *server_ctx;
} remote_ctx_t;
#endif // _UDPRELAY_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,448 @@
/*
* utils.c - Misc utilities
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#ifndef __MINGW32__
#include <pwd.h>
#include <grp.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "utils.h"
#ifdef HAVE_SETRLIMIT
#include <sys/time.h>
#include <sys/resource.h>
#endif
#define INT_DIGITS 19 /* enough for 64 bit integer */
#ifdef LIB_ONLY
FILE *logfile;
#endif
#ifdef HAS_SYSLOG
int use_syslog = 0;
#endif
#ifndef __MINGW32__
void
ERROR(const char *s)
{
char *msg = strerror(errno);
LOGE("%s: %s", s, msg);
}
#endif
int use_tty = 1;
char *
ss_itoa(int i)
{
/* Room for INT_DIGITS digits, - and '\0' */
static char buf[INT_DIGITS + 2];
char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */
if (i >= 0) {
do {
*--p = '0' + (i % 10);
i /= 10;
} while (i != 0);
return p;
} else { /* i < 0 */
do {
*--p = '0' - (i % 10);
i /= 10;
} while (i != 0);
*--p = '-';
}
return p;
}
int
ss_isnumeric(const char *s) {
if (!s || !*s)
return 0;
while (isdigit(*s))
++s;
return *s == '\0';
}
/*
* setuid() and setgid() for a specified user.
*/
int
run_as(const char *user)
{
#ifndef __MINGW32__
if (user[0]) {
/* Convert user to a long integer if it is a non-negative number.
* -1 means it is a user name. */
long uid = -1;
if (ss_isnumeric(user)) {
errno = 0;
char *endptr;
uid = strtol(user, &endptr, 10);
if (errno || endptr == user)
uid = -1;
}
#ifdef HAVE_GETPWNAM_R
struct passwd pwdbuf, *pwd;
memset(&pwdbuf, 0, sizeof(struct passwd));
size_t buflen;
int err;
for (buflen = 128;; buflen *= 2) {
char buf[buflen]; /* variable length array */
/* Note that we use getpwnam_r() instead of getpwnam(),
* which returns its result in a statically allocated buffer and
* cannot be considered thread safe. */
err = uid >= 0 ? getpwuid_r((uid_t)uid, &pwdbuf, buf, buflen, &pwd)
: getpwnam_r(user, &pwdbuf, buf, buflen, &pwd);
if (err == 0 && pwd) {
/* setgid first, because we may not be allowed to do it anymore after setuid */
if (setgid(pwd->pw_gid) != 0) {
LOGE(
"Could not change group id to that of run_as user '%s': %s",
pwd->pw_name, strerror(errno));
return 0;
}
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name);
return 0;
}
if (setuid(pwd->pw_uid) != 0) {
LOGE(
"Could not change user id to that of run_as user '%s': %s",
pwd->pw_name, strerror(errno));
return 0;
}
break;
} else if (err != ERANGE) {
if (err) {
LOGE("run_as user '%s' could not be found: %s", user,
strerror(err));
} else {
LOGE("run_as user '%s' could not be found.", user);
}
return 0;
} else if (buflen >= 16 * 1024) {
/* If getpwnam_r() seems defective, call it quits rather than
* keep on allocating ever larger buffers until we crash. */
LOGE(
"getpwnam_r() requires more than %u bytes of buffer space.",
(unsigned)buflen);
return 0;
}
/* Else try again with larger buffer. */
}
#else
/* No getpwnam_r() :-( We'll use getpwnam() and hope for the best. */
struct passwd *pwd;
if (!(pwd = uid >=0 ? getpwuid((uid_t)uid) : getpwnam(user))) {
LOGE("run_as user %s could not be found.", user);
return 0;
}
/* setgid first, because we may not allowed to do it anymore after setuid */
if (setgid(pwd->pw_gid) != 0) {
LOGE("Could not change group id to that of run_as user '%s': %s",
pwd->pw_name, strerror(errno));
return 0;
}
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name);
return 0;
}
if (setuid(pwd->pw_uid) != 0) {
LOGE("Could not change user id to that of run_as user '%s': %s",
pwd->pw_name, strerror(errno));
return 0;
}
#endif
}
#endif // __MINGW32__
return 1;
}
char *
ss_strndup(const char *s, size_t n)
{
size_t len = strlen(s);
char *ret;
if (len <= n) {
return strdup(s);
}
ret = ss_malloc(n + 1);
strncpy(ret, s, n);
ret[n] = '\0';
return ret;
}
void
FATAL(const char *msg)
{
LOGE("%s", msg);
exit(-1);
}
void *
ss_malloc(size_t size)
{
void *tmp = malloc(size);
if (tmp == NULL)
exit(EXIT_FAILURE);
return tmp;
}
void *
ss_realloc(void *ptr, size_t new_size)
{
void *new = realloc(ptr, new_size);
if (new == NULL) {
free(ptr);
ptr = NULL;
exit(EXIT_FAILURE);
}
return new;
}
void
usage()
{
printf("\n");
printf("shadowsocks-libev %s with %s\n\n", VERSION, USING_CRYPTO);
printf(
" maintained by Max Lv <max.c.lv@gmail.com> and Linus Yang <laokongzi@gmail.com>\n\n");
printf(" usage:\n\n");
#ifdef MODULE_LOCAL
printf(" ss-local\n");
#elif MODULE_REMOTE
printf(" ss-server\n");
#elif MODULE_TUNNEL
printf(" ss-tunnel\n");
#elif MODULE_REDIR
printf(" ss-redir\n");
#elif MODULE_MANAGER
printf(" ss-manager\n");
#endif
printf("\n");
printf(
" -s <server_host> Host name or IP address of your remote server.\n");
printf(
" -p <server_port> Port number of your remote server.\n");
printf(
" -l <local_port> Port number of your local server.\n");
printf(
" -k <password> Password of your remote server.\n");
printf(
" -m <encrypt_method> Encrypt method: table, rc4, rc4-md5,\n");
printf(
" aes-128-cfb, aes-192-cfb, aes-256-cfb,\n");
printf(
" aes-128-ctr, aes-192-ctr, aes-256-ctr,\n");
printf(
" bf-cfb, camellia-128-cfb, camellia-192-cfb,\n");
printf(
" camellia-256-cfb, cast5-cfb, des-cfb,\n");
printf(
" idea-cfb, rc2-cfb, seed-cfb, salsa20,\n");
printf(
" chacha20 and chacha20-ietf.\n");
printf(
" The default cipher is rc4-md5.\n");
printf("\n");
printf(
" [-a <user>] Run as another user.\n");
printf(
" [-f <pid_file>] The file path to store pid.\n");
printf(
" [-t <timeout>] Socket timeout in seconds.\n");
printf(
" [-c <config_file>] The path to config file.\n");
#ifdef HAVE_SETRLIMIT
printf(
" [-n <number>] Max number of open files.\n");
#endif
#ifndef MODULE_REDIR
printf(
" [-i <interface>] Network interface to bind.\n");
#endif
printf(
" [-b <local_address>] Local address to bind.\n");
printf("\n");
printf(
" [-u] Enable UDP relay.\n");
#ifdef MODULE_REDIR
printf(
" TPROXY is required in redir mode.\n");
#endif
printf(
" [-U] Enable UDP relay and disable TCP relay.\n");
printf(
" [-A] Enable onetime authentication.\n");
#ifdef MODULE_REMOTE
printf(
" [-6] Resovle hostname to IPv6 address first.\n");
#endif
printf("\n");
#ifdef MODULE_TUNNEL
printf(
" [-L <addr>:<port>] Destination server address and port\n");
printf(
" for local port forwarding.\n");
#endif
#ifdef MODULE_REMOTE
printf(
" [-d <addr>] Name servers for internal DNS resolver.\n");
#endif
#if defined(MODULE_REMOTE) || defined(MODULE_LOCAL)
printf(
" [--fast-open] Enable TCP fast open.\n");
printf(
" with Linux kernel > 3.7.0.\n");
printf(
" [--acl <acl_file>] Path to ACL (Access Control List).\n");
#endif
#if defined(MODULE_REMOTE) || defined(MODULE_MANAGER)
printf(
" [--manager-address <addr>] UNIX domain socket address.\n");
#endif
#ifdef MODULE_MANAGER
printf(
" [--executable <path>] Path to the executable of ss-server.\n");
#endif
printf(
" [--mtu <MTU>] MTU of your network interface.\n");
#ifdef __linux__
printf(
" [--mptcp] Enable Multipath TCP on MPTCP Kernel.\n");
#ifdef MODULE_REMOTE
printf(
" [--firewall] Setup firewall rules for auto blocking.\n");
#endif
#endif
printf("\n");
printf(
" [-v] Verbose mode.\n");
printf(
" [-h, --help] Print this message.\n");
printf("\n");
}
void
daemonize(const char *path)
{
#ifndef __MINGW32__
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
* we can exit the parent process. */
if (pid > 0) {
FILE *file = fopen(path, "w");
if (file == NULL) {
FATAL("Invalid pid file\n");
}
fprintf(file, "%d", (int)pid);
fclose(file);
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
/* Open any logs here */
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
#endif
}
#ifdef HAVE_SETRLIMIT
int
set_nofile(int nofile)
{
struct rlimit limit = { nofile, nofile }; /* set both soft and hard limit */
if (nofile <= 0) {
FATAL("nofile must be greater than 0\n");
}
if (setrlimit(RLIMIT_NOFILE, &limit) < 0) {
if (errno == EPERM) {
LOGE(
"insufficient permission to change NOFILE, not starting as root?");
return -1;
} else if (errno == EINVAL) {
LOGE("invalid nofile, decrease nofile and try again");
return -1;
} else {
LOGE("setrlimit failed: %s", strerror(errno));
return -1;
}
}
return 0;
}
#endif

View File

@ -0,0 +1,232 @@
/*
* utils.h - Misc utilities
*
* Copyright (C) 2013 - 2016, Max Lv <max.c.lv@gmail.com>
*
* This file is part of the shadowsocks-libev.
*
* shadowsocks-libev is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* shadowsocks-libev is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with shadowsocks-libev; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
#if defined(USE_CRYPTO_OPENSSL)
#include <openssl/opensslv.h>
#define USING_CRYPTO OPENSSL_VERSION_TEXT
#elif defined(USE_CRYPTO_POLARSSL)
#include <polarssl/version.h>
#define USING_CRYPTO POLARSSL_VERSION_STRING_FULL
#elif defined(USE_CRYPTO_MBEDTLS)
#include <mbedtls/version.h>
#define USING_CRYPTO MBEDTLS_VERSION_STRING_FULL
#endif
#ifndef _UTILS_H
#define _UTILS_H
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define PORTSTRLEN 16
#define SS_ADDRSTRLEN (INET6_ADDRSTRLEN + PORTSTRLEN + 1)
#ifdef ANDROID
#include <android/log.h>
#define USE_TTY()
#define USE_SYSLOG(ident)
#define LOGI(...) \
((void)__android_log_print(ANDROID_LOG_DEBUG, "shadowsocks", \
__VA_ARGS__))
#define LOGE(...) \
((void)__android_log_print(ANDROID_LOG_ERROR, "shadowsocks", \
__VA_ARGS__))
#else
#define STR(x) # x
#define TOSTR(x) STR(x)
#ifdef LIB_ONLY
extern FILE *logfile;
#define TIME_FORMAT "%Y-%m-%d %H:%M:%S"
#define USE_TTY()
#define USE_SYSLOG(ident)
#define USE_LOGFILE(ident) \
do { \
if (ident != NULL) { logfile = fopen(ident, "w+"); } } \
while (0)
#define CLOSE_LOGFILE \
do { \
if (logfile != NULL) { fclose(logfile); } } \
while (0)
#define LOGI(format, ...) \
do { \
if (logfile != NULL) { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
fprintf(logfile, " %s INFO: " format "\n", timestr, ## __VA_ARGS__); \
fflush(logfile); } \
} \
while (0)
#define LOGE(format, ...) \
do { \
if (logfile != NULL) { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
fprintf(logfile, " %s ERROR: " format "\n", timestr, \
## __VA_ARGS__); \
fflush(logfile); } \
} \
while (0)
#elif defined(_WIN32)
#define TIME_FORMAT "%Y-%m-%d %H:%M:%S"
#define USE_TTY()
#define USE_SYSLOG(ident)
#define LOGI(format, ...) \
do { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
fprintf(stderr, " %s INFO: " format "\n", timestr, ## __VA_ARGS__); \
fflush(stderr); } \
while (0)
#define LOGE(format, ...) \
do { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
fprintf(stderr, " %s ERROR: " format "\n", timestr, ## __VA_ARGS__); \
fflush(stderr); } \
while (0)
#else
#include <syslog.h>
extern int use_tty;
#define USE_TTY() \
do { \
use_tty = isatty(STDERR_FILENO); \
} while (0) \
#define HAS_SYSLOG
extern int use_syslog;
#define TIME_FORMAT "%F %T"
#define USE_SYSLOG(ident) \
do { \
use_syslog = 1; \
openlog((ident), LOG_CONS | LOG_PID, 0); } \
while (0)
#define LOGI(format, ...) \
do { \
if (use_syslog) { \
syslog(LOG_INFO, format, ## __VA_ARGS__); \
} else { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
if (use_tty) { \
fprintf(stderr, "\e[01;32m %s INFO: \e[0m" format "\n", timestr, \
## __VA_ARGS__); \
} else { \
fprintf(stderr, " %s INFO: " format "\n", timestr, \
## __VA_ARGS__); \
} \
} \
} \
while (0)
#define LOGE(format, ...) \
do { \
if (use_syslog) { \
syslog(LOG_ERR, format, ## __VA_ARGS__); \
} else { \
time_t now = time(NULL); \
char timestr[20]; \
strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \
if (use_tty) { \
fprintf(stderr, "\e[01;35m %s ERROR: \e[0m" format "\n", timestr, \
## __VA_ARGS__); \
} else { \
fprintf(stderr, " %s ERROR: " format "\n", timestr, \
## __VA_ARGS__); \
} \
} } \
while (0)
#endif
/* _WIN32 */
#endif
#ifdef __MINGW32__
#ifdef ERROR
#undef ERROR
#endif
#define ERROR(s) ss_error(s)
#else
void ERROR(const char *s);
#endif
char *ss_itoa(int i);
int ss_isnumeric(const char *s);
int run_as(const char *user);
void FATAL(const char *msg);
void usage(void);
void daemonize(const char *path);
char *ss_strndup(const char *s, size_t n);
#ifdef HAVE_SETRLIMIT
int set_nofile(int nofile);
#endif
void *ss_malloc(size_t size);
void *ss_realloc(void *ptr, size_t new_size);
#define ss_free(ptr) \
do { \
free(ptr); \
ptr = NULL; \
} while (0)
#endif // _UTILS_H

View File

@ -0,0 +1,188 @@
#include "verify.h"
static int verify_simple_pack_unit_size = 2000;
typedef struct verify_simple_local_data {
char * recv_buffer;
int recv_buffer_size;
}verify_simple_local_data;
void verify_simple_local_data_init(verify_simple_local_data* local) {
local->recv_buffer = (char*)malloc(16384);
local->recv_buffer_size = 0;
}
obfs * verify_simple_new_obfs() {
obfs * self = new_obfs();
self->l_data = malloc(sizeof(verify_simple_local_data));
verify_simple_local_data_init((verify_simple_local_data*)self->l_data);
return self;
}
void verify_simple_dispose(obfs *self) {
verify_simple_local_data *local = (verify_simple_local_data*)self->l_data;
if (local->recv_buffer != NULL) {
free(local->recv_buffer);
local->recv_buffer = NULL;
}
free(local);
self->l_data = NULL;
dispose_obfs(self);
}
int verify_simple_pack_data(char *data, int datalength, char *outdata) {
unsigned char rand_len = (xorshift128plus() & 0xF) + 1;
int out_size = rand_len + datalength + 6;
outdata[0] = out_size >> 8;
outdata[1] = out_size;
outdata[2] = rand_len;
memmove(outdata + rand_len + 2, data, datalength);
fillcrc32((unsigned char *)outdata, out_size);
return out_size;
}
int verify_simple_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t *capacity) {
char *plaindata = *pplaindata;
//verify_simple_local_data *local = (verify_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 32);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
while ( len > verify_simple_pack_unit_size ) {
pack_len = verify_simple_pack_data(data, verify_simple_pack_unit_size, buffer);
buffer += pack_len;
data += verify_simple_pack_unit_size;
len -= verify_simple_pack_unit_size;
}
if (len > 0) {
pack_len = verify_simple_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int verify_simple_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t *capacity) {
char *plaindata = *pplaindata;
verify_simple_local_data *local = (verify_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
return -1;
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
while (local->recv_buffer_size > 2) {
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
if (length > local->recv_buffer_size)
break;
int crc = crc32((unsigned char*)recv_buffer, length);
if (crc != -1) {
free(out_buffer);
local->recv_buffer_size = 0;
return -1;
}
int data_size = length - recv_buffer[2] - 6;
memmove(buffer, recv_buffer + 2 + recv_buffer[2], data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int verify_simple_server_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t *capacity) {
char *plaindata = *pplaindata;
//verify_simple_local_data *local = (verify_simple_local_data*)self->l_data;
char * out_buffer = (char*)malloc(datalength * 2 + 32);
char * buffer = out_buffer;
char * data = plaindata;
int len = datalength;
int pack_len;
while ( len > verify_simple_pack_unit_size ) {
pack_len = verify_simple_pack_data(data, verify_simple_pack_unit_size, buffer);
buffer += pack_len;
data += verify_simple_pack_unit_size;
len -= verify_simple_pack_unit_size;
}
if (len > 0) {
pack_len = verify_simple_pack_data(data, len, buffer);
buffer += pack_len;
}
len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}
int verify_simple_server_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t *capacity) {
char *plaindata = *pplaindata;
verify_simple_local_data *local = (verify_simple_local_data*)self->l_data;
uint8_t * recv_buffer = (uint8_t *)local->recv_buffer;
if (local->recv_buffer_size + datalength > 16384)
{
LOGE("verify_simple: wrong buf length %d", local->recv_buffer_size + datalength);
return -1;
}
memmove(recv_buffer + local->recv_buffer_size, plaindata, datalength);
local->recv_buffer_size += datalength;
char * out_buffer = (char*)malloc(local->recv_buffer_size);
char * buffer = out_buffer;
while (local->recv_buffer_size > 2) {
int length = ((int)recv_buffer[0] << 8) | recv_buffer[1];
if (length >= 8192 || length < 7) {
free(out_buffer);
local->recv_buffer_size = 0;
LOGE("verify_simple: wrong length %d", length);
return -1;
}
if (length > local->recv_buffer_size)
break;
int crc = crc32((unsigned char*)recv_buffer, length);
if (crc != -1) {
free(out_buffer);
local->recv_buffer_size = 0;
LOGE("verify_simple: wrong crc");
return -1;
}
int data_size = length - recv_buffer[2] - 6;
memmove(buffer, recv_buffer + 2 + recv_buffer[2], data_size);
buffer += data_size;
memmove(recv_buffer, recv_buffer + length, local->recv_buffer_size -= length);
}
int len = buffer - out_buffer;
if (*capacity < len) {
*pplaindata = (char*)realloc(*pplaindata, *capacity = len * 2);
plaindata = *pplaindata;
}
memmove(plaindata, out_buffer, len);
free(out_buffer);
return len;
}

View File

@ -0,0 +1,19 @@
/*
* verify.h - Define shadowsocksR server's buffers and callbacks
*
* Copyright (C) 2015 - 2016, Break Wa11 <mmgac001@gmail.com>
*/
#ifndef _VERIFY_H
#define _VERIFY_H
obfs * verify_simple_new_obfs();
void verify_simple_dispose(obfs *self);
int verify_simple_client_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int verify_simple_client_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int verify_simple_server_pre_encrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
int verify_simple_server_post_decrypt(obfs *self, char **pplaindata, int datalength, size_t* capacity);
#endif // _VERIFY_H