├── debian ├── compat ├── docs ├── source │ └── format ├── patches │ ├── series │ └── 0001-Use-libcork-dev-in-system.patch ├── install ├── watch ├── doc-base ├── config.json ├── rules ├── postrm ├── changelog ├── control ├── postinst └── copyright ├── autogen.sh ├── Makefile.am ├── .gitmodules ├── AUTHORS ├── .travis.yml ├── doc ├── manpage-normal.xsl ├── manpage-bold-literal.xsl ├── asciidoc.conf ├── manpage-base.xsl ├── Makefile.am ├── obfs-server.asciidoc └── obfs-local.asciidoc ├── scripts ├── git_version.sh └── git_archive.sh ├── COPYING ├── Changes ├── APKBUILD ├── src ├── obfs_http.h ├── options.h ├── Makefile.am ├── encrypt.h ├── obfs.h ├── base64.h ├── jconf.h ├── common.h ├── server.h ├── local.h ├── encrypt.c ├── android.c ├── options.c ├── win32.h ├── netutils.h ├── base64.c ├── obfs_tls.h ├── win32.c ├── json.h ├── jconf.c ├── utils.h ├── obfs_http.c ├── netutils.c ├── utils.c └── obfs_tls.c ├── .gitignore ├── m4 ├── inet_ntop.m4 ├── stack-protector.m4 └── ax_tls.m4 ├── rpm ├── genrpm.sh └── SPECS │ └── shadowsocks-simple-obfs.spec.in ├── README.md ├── configure.ac └── INSTALL /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | README.md 3 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install --force 4 | -------------------------------------------------------------------------------- /debian/patches/series: -------------------------------------------------------------------------------- 1 | 0001-Use-libcork-dev-in-system.patch 2 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | debian/config.json usr/share/simple-obfs 2 | src/obfs-server usr/bin/ 3 | src/obfs-local usr/bin/ 4 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = libcork src 2 | 3 | if ENABLE_DOCUMENTATION 4 | SUBDIRS += doc 5 | endif 6 | 7 | ACLOCAL_AMFLAGS = -I m4 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libcork"] 2 | path = libcork 3 | url = https://github.com/shadowsocks/libcork.git 4 | ignore = dirty 5 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | 3 | opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%simple-obfs_$1.orig.tar.gz%" \ 4 | https://github.com/shadowsocks/simple-obfs/tags \ 5 | (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS -- 2 | people who have submitted patches, fixed bugs, added translations, and 3 | generally made simple-obfs that much better: 4 | 5 | https://github.com/shadowsocks/simple-obfs/graphs/contributors 6 | -------------------------------------------------------------------------------- /debian/doc-base: -------------------------------------------------------------------------------- 1 | Document: simple-obfs 2 | Title: simple-obfs documentation 3 | Author: Max Lv 4 | Abstract: This is the documentation of simple-obfs for shadowsocks 5 | Section: Network/Communication 6 | 7 | Format: HTML 8 | Index: /usr/share/doc/simple-obfs/obfs-server.html 9 | Files: /usr/share/doc/simple-obfs/*.html 10 | -------------------------------------------------------------------------------- /debian/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server":"127.0.0.1", 3 | "server_port":8388, 4 | "local_port":1080, 5 | "password":"barfoo!", 6 | "timeout":60, 7 | "method":"chacha20-ietf-poly1305", 8 | "mode":"tcp_and_udp", 9 | "fast_open":true, 10 | "plugin":"obfs-server", 11 | "plugin_opts":"obfs=tls;failover=127.0.0.1:8443;fast-open" 12 | } 13 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | #export DH_VERBOSE = 1 3 | 4 | # Security Hardening 5 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 6 | 7 | override_dh_auto_configure: 8 | # Whether to have stack-protector is decided by dpkg-buildflags. 9 | # So --disable-ssp here should be safe. 10 | # See Bug in parent project: #829498 11 | dh_auto_configure -- \ 12 | --disable-ssp 13 | 14 | %: 15 | dh $@ 16 | -------------------------------------------------------------------------------- /debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | case "$1" in 6 | purge) 7 | rm -f /etc/shadowsocks-libev/config-obfs.json 8 | test -f /etc/shadowsocks-libev/* \ 9 | || rm -r /etc/shadowsocks-libev/ 10 | ;; 11 | remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 12 | exit 0 13 | ;; 14 | *) 15 | echo "postrm called with unknown argument \`$1'" >&2 16 | exit 0 17 | ;; 18 | esac 19 | 20 | #DEBHELPER# 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | { 2 | "sudo": "required", 3 | "language": "c", 4 | "dist": "trusty", 5 | "before_script": [ 6 | "sudo apt-get install --no-install-recommends -y build-essential autoconf libtool libssl-dev libpcre3-dev libc-ares-dev libev-dev asciidoc xmlto automake", 7 | "git submodule update --init --recursive", 8 | "chmod +x *.sh", 9 | "./autogen.sh", 10 | "./configure && make" 11 | ], 12 | "script": "sudo make install", 13 | "group": "stable", 14 | "os": "linux" 15 | } 16 | -------------------------------------------------------------------------------- /doc/manpage-normal.xsl: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 9 | 10 | \ 11 | . 12 | 13 | 14 | -------------------------------------------------------------------------------- /scripts/git_version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # determine version and release number 5 | GIT_DESCRIBE=$(git describe --tags --match 'v*' --long) 6 | # GIT_DESCRIBE is like v3.0.3-11-g1e3f35c-dirty 7 | if [[ ! "$GIT_DESCRIBE" =~ ^v([^-]+)-([0-9]+)-g([0-9a-f]+)$ ]]; then 8 | >&2 echo 'ERROR - unrecognized `git describe` output: '"$GIT_DESCRIBE" 9 | exit 1 10 | fi 11 | 12 | version=${BASH_REMATCH[1]} 13 | commits=${BASH_REMATCH[2]} 14 | short_hash=${BASH_REMATCH[3]} 15 | 16 | release=1 17 | if [ "${commits}" -gt 0 ] ; then 18 | release+=.${commits}.git${short_hash} 19 | fi 20 | 21 | echo "${version} ${release}" 22 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This program is free software: you can redistribute it and/or modify 2 | it under the terms of the GNU General Public License as published by 3 | the Free Software Foundation, either version 3 of the License, or 4 | (at your option) any later version. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | -------------------------------------------------------------------------------- /doc/manpage-bold-literal.xsl: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 9 | 10 | 11 | fB 12 | 13 | 14 | fR 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | simple-obfs (0.0.5-1) unstable; urgency=medium 2 | 3 | * Fix the building issue on Windows. 4 | 5 | -- Max Lv Thu, 16 Nov 2017 18:04:07 +0800 6 | 7 | simple-obfs (0.0.4-1) unstable; urgency=medium 8 | 9 | * Minor bug fixes. 10 | 11 | -- Max Lv Mon, 06 Nov 2017 14:52:48 +0800 12 | 13 | simple-obfs (0.0.3-1) unstable; urgency=medium 14 | 15 | * Add failover option. 16 | * Minor bug fixes. 17 | 18 | -- Max Lv Fri, 17 Mar 2017 17:02:43 +0800 19 | 20 | simple-obfs (0.0.2-1) UNRELEASED; urgency=low 21 | 22 | * Initial release. (Closes: #) 23 | 24 | -- Roger Shimizu Wed, 22 Feb 2017 21:55:18 +0900 25 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | simple-obfs (0.0.5-1) unstable; urgency=medium 2 | 3 | * Fix the building issue on Windows. 4 | 5 | -- Max Lv Thu, 16 Nov 2017 18:04:07 +0800 6 | 7 | simple-obfs (0.0.4-1) unstable; urgency=medium 8 | 9 | * Minor bug fixes. 10 | 11 | -- Max Lv Mon, 06 Nov 2017 14:52:48 +0800 12 | 13 | simple-obfs (0.0.3-1) unstable; urgency=medium 14 | 15 | * Add failover option. 16 | * Minor bug fixes. 17 | 18 | -- Max Lv Fri, 17 Mar 2017 17:02:43 +0800 19 | 20 | simple-obfs (0.0.2-1) UNRELEASED; urgency=low 21 | 22 | * Initial release. (Closes: #) 23 | 24 | -- Roger Shimizu Wed, 22 Feb 2017 21:55:18 +0900 25 | -------------------------------------------------------------------------------- /APKBUILD: -------------------------------------------------------------------------------- 1 | # Contributor: Max Lv 2 | # Maintainer: Max Lv 3 | pkgname=simple-obfs 4 | pkgver=0.0.5 5 | pkgrel=0 6 | pkgdesc="Simple-obfs is a simple obfusacting tool, designed as plugin server of shadowsocks." 7 | url="https://github.com/shadowsocks/simple-obfs" 8 | arch="all" 9 | license="GPLv3+" 10 | makedepends="autoconf automake libtool linux-headers libev-dev asciidoc xmlto" 11 | subpackages="$pkgname-doc" 12 | builddir="$srcdir/$pkgname" 13 | 14 | prepare() { 15 | cd "$srcdir" 16 | git clone "$url" 17 | cd "$builddir" 18 | git checkout "v$pkgver" 19 | git submodule update --init --recursive 20 | } 21 | 22 | build() { 23 | cd "$builddir" 24 | ./autogen.sh 25 | ./configure --prefix=/usr 26 | make 27 | } 28 | 29 | check() { 30 | cd "$builddir" 31 | make check 32 | } 33 | 34 | package() { 35 | cd "$builddir" 36 | make DESTDIR="$pkgdir" install 37 | } 38 | -------------------------------------------------------------------------------- /doc/asciidoc.conf: -------------------------------------------------------------------------------- 1 | [tags] 2 | bracket-emphasis={1?[{1}]}<|> 3 | 4 | [quotes] 5 | <|>=#bracket-emphasis 6 | 7 | [attributes] 8 | asterisk=* 9 | plus=+ 10 | caret=^ 11 | startsb=[ 12 | endsb=] 13 | backslash=\ 14 | tilde=~ 15 | apostrophe=' 16 | backtick=` 17 | litdd=-- 18 | 19 | ifdef::doctype-manpage[] 20 | ifdef::backend-docbook[] 21 | [header] 22 | template::[header-declarations] 23 | 24 | 25 | {mantitle} 26 | {manvolnum} 27 | Shadowsocks-libev 28 | {version} 29 | Shadowsocks-libev Manual 30 | 31 | 32 | {manname} 33 | {manpurpose} 34 | 35 | endif::backend-docbook[] 36 | endif::doctype-manpage[] 37 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: simple-obfs 2 | Section: net 3 | Priority: optional 4 | Maintainer: Roger Shimizu 5 | Build-Depends: 6 | asciidoc-base | asciidoc, 7 | debhelper (>= 10), 8 | libcork-dev, 9 | libev-dev, 10 | xmlto 11 | Standards-Version: 4.1.1 12 | Homepage: https://github.com/shadowsocks/simple-obfs 13 | Vcs-Git: https://anonscm.debian.org/git/collab-maint/simple-obfs.git 14 | Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/simple-obfs.git 15 | 16 | Package: simple-obfs 17 | Architecture: any 18 | Multi-Arch: foreign 19 | Depends: 20 | libcap2-bin [linux-any], 21 | shadowsocks-libev (>= 3.0.5), 22 | ${misc:Depends}, 23 | ${shlibs:Depends} 24 | Description: simple obfusacting plugin for shadowsocks-libev 25 | Simple-obfs is a simple obfusacting tool, designed as plugin 26 | server/client of shadowsocks-libev. 27 | . 28 | Simple-obfs is written in pure C and takes advantage of libev to 29 | achieve both high performance and low resource consumption. 30 | -------------------------------------------------------------------------------- /src/obfs_http.h: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs_http.h - Interfaces of http obfuscating function 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef OBFS_HTTP_H 24 | #define OBFS_HTTP_H 25 | 26 | #include "obfs.h" 27 | 28 | extern obfs_para_t *obfs_http; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # POSIX-compliant maint function recommend by devref 6 | # to check for the existence of a command 7 | # https://www.debian.org/doc/manuals/developers-reference/ch06.html#bpp-debian-maint-scripts 8 | pathfind() { 9 | OLDIFS="$IFS" 10 | IFS=: 11 | for p in $PATH; do 12 | if [ -x "$p/$*" ]; then 13 | IFS="$OLDIFS" 14 | return 0 15 | fi 16 | done 17 | IFS="$OLDIFS" 18 | return 1 19 | } 20 | 21 | case "$1" in 22 | configure|reconfigure) 23 | pathfind setcap && setcap \ 24 | cap_net_bind_service+ep /usr/bin/obfs-server 25 | if [ ! -f /etc/shadowsocks-libev/config-obfs.json ]; then 26 | set +e 27 | pathfind apg 28 | if [ $? -eq 0 ]; then 29 | passwd=$(apg -n 1 -M ncl) 30 | else 31 | passwd=$(pwgen 12 1) 32 | fi 33 | set -e 34 | mkdir -p /etc/shadowsocks-libev 35 | sed "s/barfoo!/$passwd/" /usr/share/simple-obfs/config.json \ 36 | > /etc/shadowsocks-libev/config-obfs.json 37 | fi 38 | ;; 39 | abort-upgrade|abort-remove|abort-deconfigure) 40 | exit 0 41 | ;; 42 | *) 43 | echo "postinst called with unknown argument \`$1'" >&2 44 | exit 0 45 | ;; 46 | esac 47 | 48 | #DEBHELPER# 49 | 50 | exit 0 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore files generated by autoconf 2 | Makefile.in 3 | aclocal.m4 4 | auto/ 5 | config.h.in 6 | configure 7 | doc/Makefile.in 8 | m4/libtool.m4 9 | m4/ltoptions.m4 10 | m4/ltsugar.m4 11 | m4/ltversion.m4 12 | m4/lt~obsolete.m4 13 | src/Makefile.in 14 | 15 | # Ignore files generated by configure 16 | build/ 17 | .deps/ 18 | /Makefile 19 | src/Makefile 20 | libev/Makefile 21 | libudns/Makefile 22 | libcork/Makefile 23 | libipset/Makefile 24 | doc/Makefile 25 | autom4te.cache/ 26 | /config.h 27 | config.log 28 | config.status 29 | libtool 30 | pid 31 | src/obfs-* 32 | stamp-h1 33 | .libs 34 | .pc 35 | .dirstamp 36 | libsodium/src/libsodium/include/sodium/version.h 37 | 38 | # Ignore per-project vim config 39 | .vimrc 40 | 41 | # Ignore garbage of OS X 42 | *.DS_Store 43 | 44 | # Ignore vim cache 45 | *.swp 46 | 47 | # Documentation files 48 | doc/*.1 49 | doc/*.8 50 | doc/*.gz 51 | doc/*.xml 52 | doc/*.html 53 | 54 | # Do not edit the following section 55 | # Edit Compile Debug Document Distribute 56 | *~ 57 | *.bak 58 | *.bin 59 | *.dll 60 | *.exe 61 | *-ISO*.bdf 62 | *-JIS*.bdf 63 | *-KOI8*.bdf 64 | *.kld 65 | *.ko 66 | *.ko.cmd 67 | *.lai 68 | *.l[oa] 69 | *.[oa] 70 | *.obj 71 | *.patch 72 | *.so 73 | *.pcf.gz 74 | *.pdb 75 | *.tar.bz2 76 | *.tar.gz 77 | # 78 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * options.h - Define the interface for parsing SS_PLUGIN_OPTIONS 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * simple-obfs is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * simple-obfs is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with simple-obfs; see the file COPYING. If not, see 19 | * . 20 | */ 21 | 22 | #ifndef _OPTIONS_H 23 | #define _OPTIONS_H 24 | 25 | #define MAX_OPTION_NUM 16 26 | 27 | typedef struct options { 28 | size_t num; 29 | char *keys[MAX_OPTION_NUM]; 30 | char *values[MAX_OPTION_NUM]; 31 | } options_t; 32 | 33 | int parse_options(char *str, size_t str_len, options_t *opts); 34 | const char *get_opt(const char *key, options_t *opts); 35 | 36 | #endif // _OPTIONS_H 37 | -------------------------------------------------------------------------------- /doc/manpage-base.xsl: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 18 | 19 | 20 | 21 | sp 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | br 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | VERSION_INFO = 2:0:0 2 | 3 | AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE 4 | AM_CFLAGS += $(PTHREAD_CFLAGS) 5 | AM_CFLAGS += -I$(top_srcdir)/libcork/include 6 | AM_CFLAGS += $(LIBPCRE_CFLAGS) 7 | 8 | OBFS_COMMON_LIBS = $(top_builddir)/libcork/libcork.la \ 9 | $(INET_NTOP_LIB) $(LIBPCRE_LIBS) 10 | OBFS_COMMON_LIBS += -lev -lm 11 | 12 | bin_PROGRAMS = obfs-local 13 | bin_PROGRAMS += obfs-server 14 | 15 | obfs_src = obfs_http.c \ 16 | obfs_tls.c \ 17 | options.c \ 18 | base64.c 19 | 20 | obfs_local_SOURCES = utils.c \ 21 | jconf.c \ 22 | json.c \ 23 | encrypt.c \ 24 | netutils.c \ 25 | local.c \ 26 | $(obfs_src) 27 | 28 | obfs_server_SOURCES = utils.c \ 29 | netutils.c \ 30 | jconf.c \ 31 | json.c \ 32 | encrypt.c \ 33 | server.c \ 34 | $(obfs_src) 35 | 36 | obfs_local_LDADD = $(OBFS_COMMON_LIBS) 37 | obfs_server_LDADD = $(OBFS_COMMON_LIBS) 38 | 39 | obfs_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL 40 | obfs_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE 41 | 42 | if BUILD_WINCOMPAT 43 | obfs_local_SOURCES += win32.c 44 | obfs_server_SOURCES += win32.c 45 | endif 46 | -------------------------------------------------------------------------------- /m4/inet_ntop.m4: -------------------------------------------------------------------------------- 1 | # inet_ntop.m4 serial 19 2 | dnl Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc. 3 | dnl This file is free software; the Free Software Foundation 4 | dnl gives unlimited permission to copy and/or distribute it, 5 | dnl with or without modifications, as long as this notice is preserved. 6 | 7 | AC_DEFUN([ss_FUNC_INET_NTOP], 8 | [ 9 | AC_REQUIRE([AC_C_RESTRICT]) 10 | 11 | dnl Most platforms that provide inet_ntop define it in libc. 12 | dnl Solaris 8..10 provide inet_ntop in libnsl instead. 13 | dnl Solaris 2.6..7 provide inet_ntop in libresolv instead. 14 | HAVE_INET_NTOP=1 15 | INET_NTOP_LIB= 16 | ss_save_LIBS=$LIBS 17 | AC_SEARCH_LIBS([inet_ntop], [nsl resolv], [], 18 | [AC_CHECK_FUNCS([inet_ntop]) 19 | if test $ac_cv_func_inet_ntop = no; then 20 | HAVE_INET_NTOP=0 21 | fi 22 | ]) 23 | LIBS=$ss_save_LIBS 24 | 25 | if test "$ac_cv_search_inet_ntop" != "no" \ 26 | && test "$ac_cv_search_inet_ntop" != "none required"; then 27 | INET_NTOP_LIB="$ac_cv_search_inet_ntop" 28 | fi 29 | 30 | AC_CHECK_HEADERS_ONCE([netdb.h]) 31 | AC_CHECK_DECLS([inet_ntop],,, 32 | [[#include 33 | #if HAVE_NETDB_H 34 | # include 35 | #endif 36 | ]]) 37 | if test $ac_cv_have_decl_inet_ntop = no; then 38 | HAVE_DECL_INET_NTOP=0 39 | fi 40 | AC_SUBST([INET_NTOP_LIB]) 41 | ]) 42 | -------------------------------------------------------------------------------- /debian/patches/0001-Use-libcork-dev-in-system.patch: -------------------------------------------------------------------------------- 1 | From: Roger Shimizu 2 | Date: Tue, 21 Feb 2017 19:07:29 +0900 3 | Subject: Use libcork-dev in system 4 | 5 | --- 6 | Makefile.am | 2 +- 7 | configure.ac | 1 - 8 | src/Makefile.am | 5 ++--- 9 | 3 files changed, 3 insertions(+), 5 deletions(-) 10 | 11 | diff --git a/Makefile.am b/Makefile.am 12 | index d5da3ab..a342e44 100644 13 | --- a/Makefile.am 14 | +++ b/Makefile.am 15 | @@ -1,4 +1,4 @@ 16 | -SUBDIRS = libcork src 17 | +SUBDIRS = src 18 | 19 | if ENABLE_DOCUMENTATION 20 | SUBDIRS += doc 21 | diff --git a/configure.ac b/configure.ac 22 | index 3c03364..73d29a9 100755 23 | --- a/configure.ac 24 | +++ b/configure.ac 25 | @@ -281,7 +281,6 @@ AM_COND_IF([ENABLE_DOCUMENTATION], 26 | ]) 27 | 28 | AC_CONFIG_FILES([Makefile 29 | - libcork/Makefile 30 | src/Makefile]) 31 | 32 | AC_OUTPUT 33 | diff --git a/src/Makefile.am b/src/Makefile.am 34 | index 6d566f9..f58b41e 100644 35 | --- a/src/Makefile.am 36 | +++ b/src/Makefile.am 37 | @@ -5,9 +5,8 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) 38 | AM_CFLAGS += -I$(top_srcdir)/libcork/include 39 | AM_CFLAGS += $(LIBPCRE_CFLAGS) 40 | 41 | -OBFS_COMMON_LIBS = $(top_builddir)/libcork/libcork.la \ 42 | - $(INET_NTOP_LIB) $(LIBPCRE_LIBS) 43 | -OBFS_COMMON_LIBS += -lev -lm 44 | +OBFS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS) 45 | +OBFS_COMMON_LIBS += -lev -lm -lcork 46 | 47 | bin_PROGRAMS = obfs-local 48 | if !BUILD_WINCOMPAT 49 | -------------------------------------------------------------------------------- /scripts/git_archive.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | archive() { 5 | export TARBALL_NAME=$1 6 | export TARBALL_OUTDIR=$2 7 | 8 | # archive this repo 9 | cd "$(git rev-parse --show-toplevel)" 10 | git archive HEAD --format=tar --prefix="${TARBALL_NAME}/" \ 11 | -o "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" 12 | # archive submodules 13 | git submodule update --init 14 | git submodule foreach --quiet 'git archive HEAD --format=tar \ 15 | --prefix="${TARBALL_NAME}/${path}/" \ 16 | -o "${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar" 17 | tar -n --concatenate --file="${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" \ 18 | "${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar"' 19 | gzip -c "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" > "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar.gz" 20 | 21 | # clean-up 22 | git submodule foreach --quiet 'rm ${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar' 23 | rm "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" 24 | } 25 | 26 | TARGET_TARBALL_NAME=shadowsocks-simple-obfs 27 | TARGET_TARBALL_DIR=$(git rev-parse --show-toplevel) 28 | 29 | while getopts "n:o:" opt 30 | do 31 | case ${opt} in 32 | o) 33 | TARGET_TARBALL_DIR=$(readlink -f -- $OPTARG) 34 | ;; 35 | n) 36 | TARGET_TARBALL_NAME=$OPTARG 37 | ;; 38 | \?) 39 | exit 1 40 | ;; 41 | esac 42 | done 43 | 44 | archive "${TARGET_TARBALL_NAME}" "${TARGET_TARBALL_DIR}" 45 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | ASCIIDOC = @ASCIIDOC@ 2 | ASCIIDOC_EXTRA = 3 | MANPAGE_XSL = manpage-normal.xsl 4 | XMLTO = @XMLTO@ 5 | XMLTO_EXTRA = -m manpage-bold-literal.xsl 6 | GZIPCMD = @GZIP@ 7 | INSTALL = @INSTALL@ 8 | RM = @RM@ 9 | MV = @MV@ 10 | SED = @SED@ 11 | VERSION = `$(SED) -n 's/.*PACKAGE_VERSION "\(.*\)"/\1/p'\ 12 | ../config.h` 13 | 14 | # Guard against environment variables 15 | if ENABLE_DOCUMENTATION 16 | MAN1_DOC = 17 | MAN1_DOC += obfs-local.1 18 | MAN1_DOC += obfs-server.1 19 | 20 | MAN8_DOC = 21 | else 22 | MAN1_DOC = 23 | MAN8_DOC = 24 | endif 25 | 26 | MAN8_XML = $(MAN8_DOC:%.8=%.xml) 27 | MAN1_XML = $(MAN1_DOC:%.1=%.xml) 28 | MAN_XML = $(MAN8_XML) $(MAN1_XML) 29 | 30 | MAN8_HTML = $(MAN8_DOC:%.8=%.html) 31 | MAN1_HTML = $(MAN1_DOC:%.1=%.html) 32 | MAN_HTML = $(MAN8_HTML) $(MAN1_HTML) 33 | 34 | MAN8_TXT = $(MAN8_DOC:%.8=%.asciidoc) 35 | MAN1_TXT = $(MAN1_DOC:%.1=%.asciidoc) 36 | MAN_TXT = $(MAN8_TXT) $(MAN1_TXT) 37 | 38 | man_MANS = $(MAN8_DOC) $(MAN1_DOC) 39 | 40 | html-local: $(MAN_HTML) 41 | 42 | %.1: %.xml 43 | $(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 44 | 45 | %.8: %.xml 46 | $(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 47 | 48 | %.xml: %.asciidoc 49 | $(AM_V_GEN)$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ 50 | -aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $< 51 | 52 | %.html: %.asciidoc 53 | $(AM_V_GEN)$(ASCIIDOC) -b html4 -d article -f asciidoc.conf \ 54 | -aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $< 55 | 56 | doc_DATA = $(MAN_HTML) 57 | CLEANFILES = $(MAN_XML) $(man_MANS) $(MAN_HTML) 58 | -------------------------------------------------------------------------------- /src/encrypt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * encrypt.h - Define the enryptor's interface 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _ENCRYPT_H 24 | #define _ENCRYPT_H 25 | 26 | #ifndef __MINGW32__ 27 | #include 28 | #else 29 | 30 | #ifdef max 31 | #undef max 32 | #endif 33 | 34 | #ifdef min 35 | #undef min 36 | #endif 37 | 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 46 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 47 | 48 | typedef struct buffer { 49 | size_t idx; 50 | size_t len; 51 | size_t capacity; 52 | char *data; 53 | } buffer_t; 54 | 55 | typedef struct chunk { 56 | uint32_t idx; 57 | uint32_t len; 58 | uint32_t counter; 59 | buffer_t *buf; 60 | } chunk_t; 61 | 62 | int balloc(buffer_t *ptr, size_t capacity); 63 | int brealloc(buffer_t *ptr, size_t len, size_t capacity); 64 | void bfree(buffer_t *ptr); 65 | 66 | int rand_bytes(void *output, int len); 67 | 68 | #endif // _ENCRYPT_H 69 | -------------------------------------------------------------------------------- /src/obfs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs.h - Interfaces of obfuscating function 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef OBFS_H 24 | #define OBFS_H 25 | 26 | #include 27 | #include "encrypt.h" 28 | 29 | #define OBFS_OK 0 30 | #define OBFS_NEED_MORE -1 31 | #define OBFS_ERROR -2 32 | 33 | typedef struct obfs { 34 | int obfs_stage; 35 | int deobfs_stage; 36 | buffer_t *buf; 37 | void *extra; 38 | } obfs_t; 39 | 40 | typedef struct obfs_para { 41 | const char *name; 42 | const char *host; 43 | const char *uri; 44 | const char *method; 45 | uint16_t port; 46 | bool send_empty_response_upon_connection; 47 | 48 | int(*const obfs_request)(buffer_t *, size_t, obfs_t *); 49 | int(*const obfs_response)(buffer_t *, size_t, obfs_t *); 50 | int(*const deobfs_request)(buffer_t *, size_t, obfs_t *); 51 | int(*const deobfs_response)(buffer_t *, size_t, obfs_t *); 52 | int(*const check_obfs)(buffer_t *); 53 | void(*const disable)(obfs_t *); 54 | int(*const is_enable)(obfs_t *); 55 | } obfs_para_t; 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) 3 | * 4 | * This file is part of FFmpeg. 5 | * 6 | * FFmpeg is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * FFmpeg is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with FFmpeg; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef BASE64_H 22 | #define BASE64_H 23 | 24 | #include 25 | 26 | /** 27 | * Decode a base64-encoded string. 28 | * 29 | * @param out buffer for decoded data 30 | * @param in null-terminated input string 31 | * @param out_size size in bytes of the out buffer, must be at 32 | * least 3/4 of the length of in 33 | * @return number of bytes written, or a negative value in case of 34 | * invalid input 35 | */ 36 | int base64_decode(uint8_t *out, const char *in, int out_size); 37 | 38 | /** 39 | * Encode data to base64 and null-terminate. 40 | * 41 | * @param out buffer for encoded data 42 | * @param out_size size in bytes of the output buffer, must be at 43 | * least BASE64_SIZE(in_size) 44 | * @param in_size size in bytes of the 'in' buffer 45 | * @return 'out' or NULL in case of error 46 | */ 47 | char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size); 48 | 49 | /** 50 | * Calculate the output size needed to base64-encode x bytes. 51 | */ 52 | #define BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) 53 | 54 | #endif /* BASE64_H */ 55 | -------------------------------------------------------------------------------- /m4/stack-protector.m4: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2007 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # GGL_CHECK_STACK_PROTECTOR([ACTION-IF-OK], [ACTION-IF-NOT-OK]) 17 | # Check if c compiler supports -fstack-protector and -fstack-protector-all 18 | # options. 19 | 20 | AC_DEFUN([GGL_CHECK_STACK_PROTECTOR], [ 21 | ggl_check_stack_protector_save_CXXFLAGS="$CXXFLAGS" 22 | ggl_check_stack_protector_save_CFLAGS="$CFLAGS" 23 | 24 | AC_MSG_CHECKING([if -fstack-protector and -fstack-protector-all are supported.]) 25 | 26 | CXXFLAGS="$CXXFLAGS -fstack-protector" 27 | CFLAGS="$CFLAGS -fstack-protector" 28 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([ 29 | int main() { 30 | return 0; 31 | } 32 | ])], 33 | [ggl_check_stack_protector_ok=yes], 34 | [ggl_check_stack_protector_ok=no]) 35 | 36 | CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS -fstack-protector-all" 37 | CFLAGS="$ggl_check_stack_protector_save_CFLAGS -fstack-protector-all" 38 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([ 39 | int main() { 40 | return 0; 41 | } 42 | ])], 43 | [ggl_check_stack_protector_all_ok=yes], 44 | [ggl_check_stack_protector_all_ok=no]) 45 | 46 | if test "x$ggl_check_stack_protector_ok" = "xyes" -a \ 47 | "x$ggl_check_stack_protector_all_ok" = "xyes"; then 48 | AC_MSG_RESULT([yes]) 49 | ifelse([$1], , :, [$1]) 50 | else 51 | AC_MSG_RESULT([no]) 52 | ifelse([$2], , :, [$2]) 53 | fi 54 | 55 | CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS" 56 | CFLAGS="$ggl_check_stack_protector_save_CFLAGS" 57 | 58 | ]) # GGL_CHECK_STACK_PROTECTOR 59 | -------------------------------------------------------------------------------- /src/jconf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * jconf.h - Define the config data structure 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * simple-obfs is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * simple-obfs is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with simple-obfs; see the file COPYING. If not, see 19 | * . 20 | */ 21 | 22 | #ifndef _JCONF_H 23 | #define _JCONF_H 24 | 25 | #define MAX_PORT_NUM 1024 26 | #define MAX_REMOTE_NUM 10 27 | #define MAX_CONF_SIZE 128 * 1024 28 | #define MAX_DNS_NUM 4 29 | #define MAX_CONNECT_TIMEOUT 10 30 | #define MAX_REQUEST_TIMEOUT 60 31 | #define MIN_UDP_TIMEOUT 10 32 | #define UPDATE_INTERVAL 5 33 | 34 | typedef struct { 35 | char *host; 36 | char *port; 37 | } ss_addr_t; 38 | 39 | typedef struct { 40 | char *port; 41 | char *password; 42 | } ss_port_password_t; 43 | 44 | typedef struct { 45 | int remote_num; 46 | ss_addr_t remote_addr[MAX_REMOTE_NUM]; 47 | char *remote_port; 48 | char *local_addr; 49 | char *local_port; 50 | char *timeout; 51 | char *user; 52 | char *obfs; 53 | char *obfs_host; 54 | char *obfs_uri; 55 | char *http_method; 56 | char *failover; 57 | int fast_open; 58 | int nofile; 59 | char *nameserver; 60 | char *dst_addr; 61 | int mptcp; 62 | int ipv6_first; 63 | int reverse_proxy; 64 | } jconf_t; 65 | 66 | jconf_t *read_jconf(const char *file); 67 | void parse_addr(const char *str, ss_addr_t *addr); 68 | void free_addr(ss_addr_t *addr); 69 | 70 | #endif // _JCONF_H 71 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h - Provide global definitions 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * simple-obfs is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * simple-obfs is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with simple-obfs; see the file COPYING. If not, see 19 | * . 20 | */ 21 | 22 | #ifndef _COMMON_H 23 | #define _COMMON_H 24 | 25 | #define DEFAULT_CONF_PATH "/etc/simple-obfs/config.json" 26 | 27 | #ifndef SOL_TCP 28 | #define SOL_TCP IPPROTO_TCP 29 | #endif 30 | 31 | #if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) 32 | #define MODULE_LOCAL 33 | #endif 34 | 35 | int init_udprelay(const char *server_host, const char *server_port, 36 | #ifdef MODULE_LOCAL 37 | const struct sockaddr *remote_addr, const int remote_addr_len, 38 | #ifdef MODULE_TUNNEL 39 | const ss_addr_t tunnel_addr, 40 | #endif 41 | #endif 42 | int mtu, int method, int auth, int timeout, const char *iface); 43 | 44 | void free_udprelay(void); 45 | 46 | #ifdef ANDROID 47 | int protect_socket(int fd); 48 | int send_traffic_stat(uint64_t tx, uint64_t rx); 49 | #endif 50 | 51 | #define STAGE_ERROR -1 /* Error detected */ 52 | #define STAGE_INIT 0 /* Initial stage */ 53 | #define STAGE_HANDSHAKE 1 /* Handshake with client */ 54 | #define STAGE_PARSE 2 /* Parse the header */ 55 | #define STAGE_RESOLVE 4 /* Resolve the hostname */ 56 | #define STAGE_STREAM 5 /* Stream between client and server */ 57 | 58 | #endif // _COMMON_H 59 | -------------------------------------------------------------------------------- /src/server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server.h - Define server's buffers and callbacks 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _SERVER_H 24 | #define _SERVER_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __MINGW32__ 31 | #include "win32.h" 32 | #endif 33 | 34 | #include "encrypt.h" 35 | #include "jconf.h" 36 | 37 | #include "common.h" 38 | 39 | typedef struct listen_ctx { 40 | ev_io io; 41 | int fd; 42 | int timeout; 43 | int method; 44 | ss_addr_t *dst_addr; 45 | ss_addr_t *failover; 46 | char *iface; 47 | struct ev_loop *loop; 48 | } listen_ctx_t; 49 | 50 | typedef struct server_ctx { 51 | ev_io io; 52 | ev_timer watcher; 53 | int connected; 54 | struct server *server; 55 | } server_ctx_t; 56 | 57 | typedef struct server { 58 | int fd; 59 | int stage; 60 | int auth; 61 | 62 | obfs_t *obfs; 63 | 64 | buffer_t *buf; 65 | buffer_t *header_buf; 66 | 67 | struct server_ctx *recv_ctx; 68 | struct server_ctx *send_ctx; 69 | struct listen_ctx *listen_ctx; 70 | struct remote *remote; 71 | 72 | struct cork_dllist_item entries; 73 | } server_t; 74 | 75 | typedef struct remote_ctx { 76 | ev_io io; 77 | int connected; 78 | struct remote *remote; 79 | } remote_ctx_t; 80 | 81 | typedef struct remote { 82 | int fd; 83 | #ifdef TCP_FASTOPEN_WINSOCK 84 | OVERLAPPED olap; 85 | int connect_ex_done; 86 | #endif 87 | buffer_t *buf; 88 | struct remote_ctx *recv_ctx; 89 | struct remote_ctx *send_ctx; 90 | struct server *server; 91 | } remote_t; 92 | 93 | #endif // _SERVER_H 94 | -------------------------------------------------------------------------------- /rpm/genrpm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | NAME=shadowsocks-simple-obfs 5 | 6 | SELF=$(readlink -f -- "$0") 7 | HERE=$(dirname -- "$SELF") 8 | 9 | SOURCES="${HERE}"/SOURCES 10 | SPEC_TEMPLATE="${HERE}"/SPECS/${NAME}.spec.in 11 | SPEC_FILE="${SPEC_TEMPLATE%%.in}" 12 | 13 | GIT_VERSION=$("${HERE}"/../scripts/git_version.sh) 14 | 15 | OPT_OUTDIR="${HERE}/SRPMS" 16 | OPT_USE_SYSTEM_LIB=0 17 | OUT_BUILD_RPM=0 18 | 19 | version=$(echo ${GIT_VERSION} | cut -d' ' -f1) 20 | release=$(echo ${GIT_VERSION} | cut -d' ' -f2) 21 | 22 | name_version=${NAME}-${version}-${release} 23 | source_name=${name_version}.tar.gz 24 | 25 | archive() 26 | { 27 | "${HERE}"/../scripts/git_archive.sh -o "${SOURCES}" -n ${name_version} 28 | } 29 | 30 | build_src_rpm() 31 | { 32 | rpmbuild -bs "${SPEC_FILE}" \ 33 | --undefine "dist" \ 34 | --define "%_topdir ${HERE}" \ 35 | --define "%_srcrpmdir ${OPT_OUTDIR}" 36 | } 37 | 38 | build_rpm() 39 | { 40 | rpmbuild --rebuild "${OPT_OUTDIR}"/${name_version}.src.rpm \ 41 | --define "%_topdir ${HERE}" \ 42 | --define "%use_system_lib ${OPT_USE_SYSTEM_LIB}" 43 | } 44 | 45 | create_spec() 46 | { 47 | sed -e "s/@NAME@/${NAME}/g" \ 48 | -e "s/@VERSION@/${version}/g" \ 49 | -e "s/@RELEASE@/${release}/g" \ 50 | -e "s/@SOURCE@/${source_name}/g" \ 51 | -e "s/@NAME_VERSION@/${name_version}/g" \ 52 | "${SPEC_TEMPLATE}" > "${SPEC_FILE}" 53 | } 54 | 55 | show_help() 56 | { 57 | echo -e "$(basename $0) [OPTION...]" 58 | echo -e "Create and build shadowsocks-simple-obfs SRPM" 59 | echo 60 | echo -e "Options:" 61 | echo -e " -h show this help." 62 | echo -e " -b use rpmbuld to build resulting SRPM" 63 | echo -e " -s use system shared libraries (RPM only)" 64 | echo -e " -o output directory" 65 | } 66 | 67 | while getopts "hbso:" opt 68 | do 69 | case ${opt} in 70 | h) 71 | show_help 72 | exit 0 73 | ;; 74 | b) 75 | OPT_BUILD_RPM=1 76 | ;; 77 | s) 78 | OPT_USE_SYSTEM_LIB=1 79 | ;; 80 | o) 81 | OPT_OUTDIR=$(readlink -f -- $OPTARG) 82 | ;; 83 | *) 84 | show_help 85 | exit 1 86 | ;; 87 | esac 88 | done 89 | 90 | create_spec 91 | archive 92 | build_src_rpm 93 | if [ "${OPT_BUILD_RPM}" = "1" ] ; then 94 | build_rpm 95 | fi 96 | -------------------------------------------------------------------------------- /src/local.h: -------------------------------------------------------------------------------- 1 | /* 2 | * local.h - Define the client's buffers and callbacks 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _LOCAL_H 24 | #define _LOCAL_H 25 | 26 | #include 27 | #include 28 | 29 | #ifdef __MINGW32__ 30 | #include "win32.h" 31 | #endif 32 | 33 | #include "encrypt.h" 34 | #include "jconf.h" 35 | 36 | #include "common.h" 37 | 38 | typedef struct listen_ctx { 39 | ev_io io; 40 | char *iface; 41 | int remote_num; 42 | int method; 43 | int timeout; 44 | int fd; 45 | int mptcp; 46 | struct sockaddr **remote_addr; 47 | } listen_ctx_t; 48 | 49 | typedef struct server_ctx { 50 | ev_io io; 51 | int connected; 52 | struct server *server; 53 | } server_ctx_t; 54 | 55 | typedef struct server { 56 | int fd; 57 | int stage; 58 | 59 | obfs_t *obfs; 60 | 61 | struct server_ctx *recv_ctx; 62 | struct server_ctx *send_ctx; 63 | struct listen_ctx *listener; 64 | struct remote *remote; 65 | 66 | buffer_t *buf; 67 | 68 | struct cork_dllist_item entries; 69 | } server_t; 70 | 71 | typedef struct remote_ctx { 72 | ev_io io; 73 | ev_timer watcher; 74 | 75 | int connected; 76 | struct remote *remote; 77 | } remote_ctx_t; 78 | 79 | typedef struct remote { 80 | int fd; 81 | int direct; 82 | int addr_len; 83 | uint32_t counter; 84 | #ifdef TCP_FASTOPEN_WINSOCK 85 | OVERLAPPED olap; 86 | int connect_ex_done; 87 | #endif 88 | 89 | buffer_t *buf; 90 | struct remote_ctx *recv_ctx; 91 | struct remote_ctx *send_ctx; 92 | struct server *server; 93 | struct sockaddr_storage addr; 94 | } remote_t; 95 | 96 | #endif // _LOCAL_H 97 | -------------------------------------------------------------------------------- /src/encrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * encrypt.c - Manage the global encryptor 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #include 24 | 25 | #ifdef HAVE_CONFIG_H 26 | #include "config.h" 27 | #endif 28 | 29 | #ifndef __MINGW32__ 30 | #include 31 | #endif 32 | 33 | #include "encrypt.h" 34 | #include "utils.h" 35 | 36 | #define OFFSET_ROL(p, o) ((uint64_t)(*(p + o)) << (8 * o)) 37 | 38 | #ifdef DEBUG 39 | static void 40 | dump(char *tag, char *text, int len) 41 | { 42 | unsigned int i; 43 | printf("%s: ", tag); 44 | for (i = 0; i < len; i++) 45 | printf("0x%02x ", (uint8_t)text[i]); 46 | printf("\n"); 47 | } 48 | #endif 49 | 50 | int 51 | balloc(buffer_t *ptr, size_t capacity) 52 | { 53 | memset(ptr, 0, sizeof(buffer_t)); 54 | ptr->data = ss_malloc(capacity); 55 | ptr->capacity = capacity; 56 | return capacity; 57 | } 58 | 59 | int 60 | brealloc(buffer_t *ptr, size_t len, size_t capacity) 61 | { 62 | if (ptr == NULL) 63 | return -1; 64 | size_t real_capacity = max(len, capacity); 65 | if (ptr->capacity < real_capacity) { 66 | ptr->data = ss_realloc(ptr->data, real_capacity); 67 | ptr->capacity = real_capacity; 68 | } 69 | return real_capacity; 70 | } 71 | 72 | void 73 | bfree(buffer_t *ptr) 74 | { 75 | if (ptr == NULL) 76 | return; 77 | ptr->idx = 0; 78 | ptr->len = 0; 79 | ptr->capacity = 0; 80 | if (ptr->data != NULL) { 81 | ss_free(ptr->data); 82 | } 83 | } 84 | 85 | int 86 | rand_bytes(void *output, int len) 87 | { 88 | 89 | int i; 90 | int *array = (int *)output; 91 | for (i = 0; i < len / sizeof(int); i++) 92 | array[i] = rand(); 93 | // always return success 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /src/android.c: -------------------------------------------------------------------------------- 1 | /* 2 | * android.c - Setup IPC for shadowsocks-android 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #ifdef HAVE_CONFIG_H 42 | #include "config.h" 43 | #endif 44 | 45 | #include "netutils.h" 46 | #include "utils.h" 47 | 48 | int 49 | protect_socket(int fd) 50 | { 51 | int sock; 52 | struct sockaddr_un addr; 53 | 54 | if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 55 | LOGE("[android] socket() failed: %s (socket fd = %d)\n", strerror(errno), sock); 56 | return -1; 57 | } 58 | 59 | // Set timeout to 1s 60 | struct timeval tv; 61 | tv.tv_sec = 1; 62 | tv.tv_usec = 0; 63 | setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); 64 | setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); 65 | 66 | memset(&addr, 0, sizeof(addr)); 67 | addr.sun_family = AF_UNIX; 68 | strncpy(addr.sun_path, "protect_path", sizeof(addr.sun_path) - 1); 69 | 70 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 71 | LOGE("[android] connect() failed for protect_path: %s (socket fd = %d)\n", 72 | strerror(errno), sock); 73 | close(sock); 74 | return -1; 75 | } 76 | 77 | if (ancil_send_fd(sock, fd)) { 78 | ERROR("[android] ancil_send_fd"); 79 | close(sock); 80 | return -1; 81 | } 82 | 83 | char ret = 0; 84 | 85 | if (recv(sock, &ret, 1, 0) == -1) { 86 | ERROR("[android] recv"); 87 | close(sock); 88 | return -1; 89 | } 90 | 91 | close(sock); 92 | return ret; 93 | } 94 | -------------------------------------------------------------------------------- /src/options.c: -------------------------------------------------------------------------------- 1 | /* 2 | * jconf.c - Parse the JSON format config file 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * simple-obfs is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * simple-obfs is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with simple-obfs; see the file COPYING. If not, see 19 | * . 20 | */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include 27 | #include 28 | 29 | #include "options.h" 30 | 31 | int 32 | parse_options(char *str, size_t str_len, options_t *opts) 33 | { 34 | int i, opt_idx; 35 | char p; 36 | 37 | i = 0; 38 | opt_idx = 0; 39 | p = '\0'; 40 | 41 | if (str == NULL || str_len == 0) return -1; 42 | 43 | opts->keys[0] = str; 44 | 45 | while (opt_idx < MAX_OPTION_NUM 46 | && i < str_len && str[i] != '\0') { 47 | char c = str[i]; 48 | switch (c) { 49 | case '\\': 50 | if (i + 1 == str_len) return -1; 51 | memmove(str + i, str + i + 1, str_len - i - 1); 52 | str_len--; 53 | str[str_len] = '\0'; 54 | break; 55 | case ';': 56 | if (p != '\\') { 57 | str[i] = '\0'; 58 | if (i + 1 < str_len) { 59 | opt_idx++; 60 | opts->keys[opt_idx] = str + i + 1; 61 | } 62 | } 63 | i++; 64 | break; 65 | case '=': 66 | if (p != '\\') { 67 | if (i + 1 == str_len) return -1; 68 | str[i] = '\0'; 69 | opts->values[opt_idx] = str + i + 1; 70 | } 71 | i++; 72 | break; 73 | default: 74 | i++; 75 | break; 76 | } 77 | p = c; 78 | } 79 | 80 | opts->num = opt_idx + 1; 81 | 82 | return opts->num; 83 | } 84 | 85 | const char* 86 | get_opt(const char *key, options_t *opts) 87 | { 88 | int i; 89 | for (i = 0; i < opts->num; i++) { 90 | if (strcmp(key, opts->keys[i]) == 0) { 91 | if (opts->values[i] != NULL) 92 | return opts->values[i]; 93 | else 94 | return key; 95 | } 96 | } 97 | return NULL; 98 | } 99 | -------------------------------------------------------------------------------- /doc/obfs-server.asciidoc: -------------------------------------------------------------------------------- 1 | obfs-server(1) 2 | ============ 3 | 4 | NAME 5 | ---- 6 | obfs-server - simple-obfs server 7 | 8 | SYNOPSIS 9 | -------- 10 | *obfs-server* 11 | [-v] [-h|--help] 12 | [-s ] [-p ] [-l ] 13 | [-r :] [-f ] [-t ] 14 | [-c ] [-i ] [-a ] 15 | [-d ] [-n ] [-b :: 31 | Set the server's hostname or IP. 32 | 33 | -p :: 34 | Set the server's port number. 35 | 36 | -a :: 37 | Run as a specific user. 38 | 39 | -f :: 40 | Start simple-obfs as a daemon with specific pid file. 41 | 42 | -t :: 43 | Set the socket timeout in seconds. The default value is 60. 44 | 45 | -c :: 46 | Use a configuration file. 47 | 48 | -n :: 49 | Specify max number of open files. 50 | + 51 | Only available on Linux. 52 | 53 | -i :: 54 | Send traffic through specific network interface. 55 | + 56 | For example, there are three interfaces in your device, 57 | which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). 58 | Meanwhile, you configure `obfs-server` to listen on 0.0.0.0:8388 and bind to eth1. 59 | That results the traffic go out through eth1, but not lo nor eth0. 60 | This option is useful to control traffic in multi-interface environment. 61 | 62 | -b :: 63 | Specify local address to bind. 64 | 65 | -6:: 66 | Resovle hostname to IPv6 address first. 67 | 68 | -d :: 69 | Setup name servers for internal DNS resolver (libudns). 70 | The default server is fetched from '/etc/resolv.conf'. 71 | 72 | --fast-open:: 73 | Enable TCP fast open. 74 | + 75 | Only available with Linux kernel > 3.7.0. 76 | 77 | --mptcp:: 78 | Enable Multipath TCP. 79 | + 80 | Only available with MPTCP enabled Linux kernel. 81 | 82 | --obfs :: 83 | Enable HTTP or TLS obfuscating. (Experimental) 84 | 85 | -v:: 86 | Enable verbose mode. 87 | 88 | -h|--help:: 89 | Print help message. 90 | 91 | EXAMPLE 92 | ------- 93 | It is recommended to use a config file when starting `obfs-server`(1). 94 | 95 | The config file is written in JSON and is easy to edit. 96 | Check out the 'SEE ALSO' section for the default path of config file. 97 | 98 | .... 99 | # Start the obfs-server 100 | obfs-server -c /etc/simple-obfs/config.json 101 | .... 102 | 103 | SEE ALSO 104 | -------- 105 | `obfs-local`(1), 106 | /etc/simple-obfs/config.json 107 | -------------------------------------------------------------------------------- /doc/obfs-local.asciidoc: -------------------------------------------------------------------------------- 1 | obfs-local(1) 2 | =========== 3 | 4 | NAME 5 | ---- 6 | obfs-local - simple-obfs client 7 | 8 | SYNOPSIS 9 | -------- 10 | *obfs-local* 11 | [-6] [-h|--help] 12 | [-s ] [-p ] [-l ] 13 | [-f ] [-t ] [-c ] 14 | [-i ] [-a ] [-b ] [--fast-open] 16 | [--obfs ] [--obfs-host ] 17 | 18 | DESCRIPTION 19 | ----------- 20 | *Obfs-simple* is a very simple obfuscating tunnel tool. 21 | 22 | *Obfs-simple* is written in pure C and takes advantage of libev to 23 | achieve both high performance and low resource consumption. 24 | 25 | *Obfs-simple* consists of two components. `obfs-local`(1) works as a standard 26 | tunnel on local machines to obfuscate TCP traffic. 27 | 28 | OPTIONS 29 | ------- 30 | 31 | -s :: 32 | Set the server's hostname or IP. 33 | 34 | -p :: 35 | Set the server's port number. 36 | 37 | -l :: 38 | Set the local port number. 39 | 40 | -a :: 41 | Run as a specific user. 42 | 43 | -f :: 44 | Start obfs-simple as a daemon with specific pid file. 45 | 46 | -t :: 47 | Set the socket timeout in seconds. The default value is 60. 48 | 49 | -c :: 50 | Use a configuration file. 51 | 52 | -n :: 53 | Specify max number of open files. 54 | + 55 | Only available on Linux. 56 | 57 | -i :: 58 | Send traffic through specific network interface. 59 | + 60 | For example, there are three interfaces in your device, 61 | which is lo (127.0.0.1), eth0 (192.168.0.1) and eth1 (192.168.0.2). 62 | Meanwhile, you configure `obfs-local` to listen on 0.0.0.0:8388 and bind to eth1. 63 | That results the traffic go out through eth1, but not lo nor eth0. 64 | This option is useful to control traffic in multi-interface environment. 65 | 66 | -b :: 67 | Specify local address to bind. 68 | 69 | -6:: 70 | Resovle hostname to IPv6 address first. 71 | 72 | --fast-open:: 73 | Enable TCP fast open. 74 | + 75 | Only available with Linux kernel > 3.7.0. 76 | 77 | --mptcp:: 78 | Enable Multipath TCP. 79 | + 80 | Only available with MPTCP enabled Linux kernel. 81 | 82 | --obfs :: 83 | Enable HTTP or TLS obfuscating. (Experimental) 84 | 85 | --obfs-host :: 86 | Specify the hostname for obfuscating. (Experimental) 87 | 88 | --obfs-uri :: 89 | Specify the HTTP path uri for obfuscating. (Experimental) 90 | 91 | -v:: 92 | Enable verbose mode. 93 | 94 | -h|--help:: 95 | Print help message. 96 | 97 | EXAMPLE 98 | ------- 99 | `obfs-local`(1) can be started from command line and run in foreground. 100 | Here is an example: 101 | .... 102 | # Start obfs-local with given parameters 103 | obfs-local -s example.com -p 12345 -l 1080 --obfs http --obfs-host www.baidu.com 104 | .... 105 | 106 | SEE ALSO 107 | -------- 108 | `obfs-server`(1), 109 | /etc/simple-obfs/config.json 110 | -------------------------------------------------------------------------------- /src/win32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * win32.h - Windows socket compatibility layer 3 | * 4 | * Copyright (C) 2013 - 2018, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _WINSOCK_H 24 | #define _WINSOCK_H 25 | 26 | #ifdef __MINGW32__ 27 | 28 | // Target NT6 29 | #ifndef WIN32_LEAN_AND_MEAN 30 | #define WIN32_LEAN_AND_MEAN 31 | #endif 32 | 33 | #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 34 | #undef _WIN32_WINNT 35 | #endif 36 | 37 | #ifndef _WIN32_WINNT 38 | #define _WIN32_WINNT 0x0600 39 | #endif 40 | 41 | // Winsock headers 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | // Override POSIX error number 48 | #ifdef errno 49 | #undef errno 50 | #endif 51 | #define errno WSAGetLastError() 52 | 53 | #ifdef EWOULDBLOCK 54 | #undef EWOULDBLOCK 55 | #endif 56 | #define EWOULDBLOCK WSAEWOULDBLOCK 57 | 58 | #ifdef CONNECT_IN_PROGRESS 59 | #undef CONNECT_IN_PROGRESS 60 | #endif 61 | #define CONNECT_IN_PROGRESS WSAEWOULDBLOCK 62 | 63 | #ifdef EOPNOTSUPP 64 | #undef EOPNOTSUPP 65 | #endif 66 | #define EOPNOTSUPP WSAEOPNOTSUPP 67 | 68 | #ifdef EPROTONOSUPPORT 69 | #undef EPROTONOSUPPORT 70 | #endif 71 | #define EPROTONOSUPPORT WSAEPROTONOSUPPORT 72 | 73 | #ifdef ENOPROTOOPT 74 | #undef ENOPROTOOPT 75 | #endif 76 | #define ENOPROTOOPT WSAENOPROTOOPT 77 | 78 | // Check if ConnectEx supported in header 79 | #ifdef WSAID_CONNECTEX 80 | // Hardcode TCP fast open option 81 | #ifndef TCP_FASTOPEN 82 | #define TCP_FASTOPEN 15 83 | #endif 84 | // Enable TFO support 85 | #define TCP_FASTOPEN_WINSOCK 1 86 | #endif 87 | 88 | // Override close function 89 | #define close(fd) closesocket(fd) 90 | 91 | // Override MinGW functions 92 | #define setsockopt(a,b,c,d,e) setsockopt(a,b,c,(const char *)(d),e) 93 | #define inet_ntop(a,b,c,d) inet_ntop(a,(void *)(b),c,d) 94 | 95 | // Override Windows built-in functions 96 | #ifdef ERROR 97 | #undef ERROR 98 | #endif 99 | #define ERROR(s) ss_error(s) 100 | 101 | // Winsock compatibility functions 102 | int setnonblocking(SOCKET socket); 103 | void winsock_init(void); 104 | void winsock_cleanup(void); 105 | #ifdef TCP_FASTOPEN_WINSOCK 106 | LPFN_CONNECTEX winsock_getconnectex(void); 107 | int winsock_dummybind(SOCKET fd, struct sockaddr *sa); 108 | #endif 109 | 110 | #endif // __MINGW32__ 111 | 112 | #endif // _WINSOCK_H 113 | -------------------------------------------------------------------------------- /src/netutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * netutils.h - Network utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef _NETUTILS_H 24 | #define _NETUTILS_H 25 | 26 | #ifdef __MINGW32__ 27 | #include "win32.h" 28 | #endif 29 | 30 | #if defined(__linux__) 31 | #include 32 | #elif !defined(__MINGW32__) 33 | #include 34 | #endif 35 | 36 | // only enable TCP_FASTOPEN on linux 37 | #if defined(__linux__) 38 | #include 39 | /* conditional define for TCP_FASTOPEN */ 40 | #ifndef TCP_FASTOPEN 41 | #define TCP_FASTOPEN 23 42 | #endif 43 | /* conditional define for MSG_FASTOPEN */ 44 | #ifndef MSG_FASTOPEN 45 | #define MSG_FASTOPEN 0x20000000 46 | #endif 47 | #endif 48 | 49 | /* Backward compatibility for MPTCP_ENABLED between kernel 3 & 4 */ 50 | #ifndef MPTCP_ENABLED 51 | #ifdef TCP_CC_INFO 52 | #define MPTCP_ENABLED 42 53 | #else 54 | #define MPTCP_ENABLED 26 55 | #endif 56 | #endif 57 | 58 | /** byte size of ip4 address */ 59 | #define INET_SIZE 4 60 | /** byte size of ip6 address */ 61 | #define INET6_SIZE 16 62 | 63 | size_t get_sockaddr_len(struct sockaddr *addr); 64 | ssize_t get_sockaddr(char *host, char *port, 65 | struct sockaddr_storage *storage, int block, 66 | int ipv6first); 67 | int set_reuseport(int socket); 68 | 69 | #ifdef SET_INTERFACE 70 | int setinterface(int socket_fd, const char *interface_name); 71 | #endif 72 | 73 | int bind_to_address(int socket_fd, const char *address); 74 | 75 | /** 76 | * Compare two sockaddrs. Imposes an ordering on the addresses. 77 | * Compares address and port. 78 | * @param addr1: address 1. 79 | * @param addr2: address 2. 80 | * @param len: lengths of addr. 81 | * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger. 82 | */ 83 | int sockaddr_cmp(struct sockaddr_storage *addr1, 84 | struct sockaddr_storage *addr2, socklen_t len); 85 | 86 | /** 87 | * Compare two sockaddrs. Compares address, not the port. 88 | * @param addr1: address 1. 89 | * @param addr2: address 2. 90 | * @param len: lengths of addr. 91 | * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger. 92 | */ 93 | int sockaddr_cmp_addr(struct sockaddr_storage *addr1, 94 | struct sockaddr_storage *addr2, socklen_t len); 95 | 96 | int validate_hostname(const char *hostname, const int hostname_len); 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /rpm/SPECS/shadowsocks-simple-obfs.spec.in: -------------------------------------------------------------------------------- 1 | %global requires pcre shadowsocks-libev >= 3.0.5 libev 2 | %global conflicts python-shadowsocks python3-shadowsocks 3 | %if 0%{?fedora} || 0%{?rhel} 4 | %global requires %{?requires} libcap 5 | %endif 6 | %if 0%{?suse_version} 7 | %global requires %{?requires} libcap-progs 8 | %endif 9 | %global project_desc shadowsocks-simple-obfs is a simple obfusacting tool, designed as plugin server of shadowsocks. 10 | 11 | %if 0%{?fedora} >= 15 || 0%{?rhel} >=7 || 0%{?suse_version} >= 1210 12 | %global use_systemd 1 13 | %else 14 | %global use_systemd 0 15 | %endif 16 | 17 | Name: @NAME@ 18 | Version: @VERSION@ 19 | Release: @RELEASE@%{?dist} 20 | Summary: A simple obfusacting tool, designed as plugin server of shadowsocks 21 | 22 | Group: Applications/Internet 23 | License: GPLv3+ 24 | URL: https://github.com/shadowsocks/simple-obfs 25 | Source0: @SOURCE@ 26 | 27 | BuildRequires: make gcc pcre-devel asciidoc xmlto automake libtool mbedtls-devel libsodium-devel >= 1.0.4 libev-devel c-ares-devel 28 | 29 | AutoReq: no 30 | Conflicts: %{?conflicts} 31 | Requires: %{?requires} 32 | 33 | %if 0%{?use_systemd} 34 | %{?systemd_requires} 35 | %if 0%{?suse_version} 36 | BuildRequires: systemd-rpm-macros 37 | %else 38 | BuildRequires: systemd 39 | %endif 40 | %endif 41 | 42 | %description 43 | %{?project_desc} 44 | 45 | %prep 46 | %setup -q -n @NAME_VERSION@ 47 | 48 | %build 49 | ./autogen.sh 50 | 51 | %if 0%{?use_system_lib} 52 | %configure --enable-shared --enable-system-shared-lib 53 | %else 54 | %configure --enable-shared 55 | %endif 56 | make %{?_smp_mflags} 57 | 58 | 59 | %install 60 | make install DESTDIR=%{buildroot} 61 | mkdir -p %{buildroot}/etc/shadowsocks-libev 62 | install -m 644 %{_builddir}/%{buildsubdir}/debian/config.json %{buildroot}%{_sysconfdir}/shadowsocks-libev/simple-obfs.json 63 | 64 | %pre 65 | 66 | 67 | %post 68 | setcap cap_net_bind_service+ep %{_bindir}/obfs-server \ 69 | cap_net_bind_service+ep %{_bindir}/obfs-local 70 | 71 | 72 | %preun 73 | %if ! 0%{?use_systemd} 74 | if [ $1 -eq 0 ]; then 75 | /sbin/service shadowsocks-libev stop > /dev/null 2>&1 || : 76 | fi 77 | %else 78 | %if 0%{?suse_version} 79 | %service_del_preun shadowsocks-libev.service 80 | %service_del_preun shadowsocks-libev-local.service 81 | %else 82 | %systemd_preun shadowsocks-libev.service 83 | %systemd_preun shadowsocks-libev-local.service 84 | if [ $1 -eq 0 ] ; then 85 | # Package removal, not upgrade 86 | systemctl stop shadowsocks-libev-server@'*'.service > /dev/null 2>&1 || : 87 | systemctl stop shadowsocks-libev-local@'*'.service > /dev/null 2>&1 || : 88 | systemctl stop shadowsocks-libev-tunnel@'*'.service > /dev/null 2>&1 || : 89 | systemctl stop shadowsocks-libev-redir@'*'.service > /dev/null 2>&1 || : 90 | fi 91 | %endif 92 | %endif 93 | 94 | %postun 95 | echo "Update your shadowsocks-libev configure file, and restart it maunally." 96 | 97 | %files 98 | %doc %{_docdir}/simple-obfs/*.html 99 | %{_bindir}/* 100 | %config(noreplace) %{_sysconfdir}/shadowsocks-libev/simple-obfs.json 101 | %doc %{_mandir}/man*/* 102 | 103 | 104 | %changelog 105 | -------------------------------------------------------------------------------- /m4/ax_tls.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_tls.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_TLS([action-if-found], [action-if-not-found]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Provides a test for the compiler support of thread local storage (TLS) 12 | # extensions. Defines TLS if it is found. Currently knows about GCC/ICC 13 | # and MSVC. I think SunPro uses the same as GCC, and Borland apparently 14 | # supports either. 15 | # 16 | # LICENSE 17 | # 18 | # Copyright (c) 2008 Alan Woodland 19 | # Copyright (c) 2010 Diego Elio Petteno` 20 | # 21 | # This program is free software: you can redistribute it and/or modify it 22 | # under the terms of the GNU General Public License as published by the 23 | # Free Software Foundation, either version 3 of the License, or (at your 24 | # option) any later version. 25 | # 26 | # This program is distributed in the hope that it will be useful, but 27 | # WITHOUT ANY WARRANTY; without even the implied warranty of 28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 29 | # Public License for more details. 30 | # 31 | # You should have received a copy of the GNU General Public License along 32 | # with this program. If not, see . 33 | # 34 | # As a special exception, the respective Autoconf Macro's copyright owner 35 | # gives unlimited permission to copy, distribute and modify the configure 36 | # scripts that are the output of Autoconf when processing the Macro. You 37 | # need not follow the terms of the GNU General Public License when using 38 | # or distributing such scripts, even though portions of the text of the 39 | # Macro appear in them. The GNU General Public License (GPL) does govern 40 | # all other use of the material that constitutes the Autoconf Macro. 41 | # 42 | # This special exception to the GPL applies to versions of the Autoconf 43 | # Macro released by the Autoconf Archive. When you make and distribute a 44 | # modified version of the Autoconf Macro, you may extend this special 45 | # exception to the GPL to apply to your modified version as well. 46 | 47 | #serial 11 48 | 49 | AC_DEFUN([AX_TLS], [ 50 | AC_MSG_CHECKING([for thread local storage (TLS) class]) 51 | AC_CACHE_VAL([ac_cv_tls], 52 | [for ax_tls_keyword in __thread '__declspec(thread)' none; do 53 | AS_CASE([$ax_tls_keyword], 54 | [none], [ac_cv_tls=none ; break], 55 | [AC_TRY_COMPILE( 56 | [#include 57 | static void 58 | foo(void) { 59 | static ] $ax_tls_keyword [ int bar; 60 | exit(1); 61 | }], 62 | [], 63 | [ac_cv_tls=$ax_tls_keyword ; break], 64 | ac_cv_tls=none 65 | )]) 66 | done 67 | ]) 68 | AC_MSG_RESULT([$ac_cv_tls]) 69 | 70 | AS_IF([test "$ac_cv_tls" != "none"], 71 | [AC_DEFINE_UNQUOTED([TLS],[$ac_cv_tls],[If the compiler supports a TLS storage class define it to that here]) 72 | m4_ifnblank([$1],[$1])], 73 | [m4_ifnblank([$2],[$2])]) 74 | ]) 75 | -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) 3 | * 4 | * This file is part of FFmpeg. 5 | * 6 | * FFmpeg is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * FFmpeg is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with FFmpeg; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | /** 22 | * @file 23 | * @brief Base64 encode/decode 24 | * @author Ryan Martell (with lots of Michael) 25 | */ 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include "config.h" 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | #include "base64.h" 35 | 36 | /* ---------------- private code */ 37 | static const uint8_t map2[] = 38 | { 39 | 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, 40 | 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 41 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 42 | 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 43 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 44 | 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 45 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 46 | 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 47 | 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 48 | 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 49 | }; 50 | 51 | int base64_decode(uint8_t *out, const char *in, int out_size) 52 | { 53 | int i, v; 54 | uint8_t *dst = out; 55 | 56 | v = 0; 57 | for (i = 0; in[i] && in[i] != '='; i++) { 58 | unsigned int index= in[i]-43; 59 | if (index >= sizeof(map2) || map2[index] == 0xff) 60 | return -1; 61 | v = (v << 6) + map2[index]; 62 | if (i & 3) { 63 | if (dst - out < out_size) { 64 | *dst++ = v >> (6 - 2 * (i & 3)); 65 | } 66 | } 67 | } 68 | 69 | return dst - out; 70 | } 71 | 72 | /***************************************************************************** 73 | * b64_encode: Stolen from VLC's http.c. 74 | * Simplified by Michael. 75 | * Fixed edge cases and made it work from data (vs. strings) by Ryan. 76 | *****************************************************************************/ 77 | 78 | char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size) 79 | { 80 | static const char b64[] = 81 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 82 | char *ret, *dst; 83 | unsigned i_bits = 0; 84 | int i_shift = 0; 85 | int bytes_remaining = in_size; 86 | 87 | if (in_size >= UINT_MAX / 4 || 88 | out_size < BASE64_SIZE(in_size)) 89 | return NULL; 90 | ret = dst = out; 91 | while (bytes_remaining) { 92 | i_bits = (i_bits << 8) + *in++; 93 | bytes_remaining--; 94 | i_shift += 8; 95 | 96 | do { 97 | *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; 98 | i_shift -= 6; 99 | } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0)); 100 | } 101 | while ((dst - ret) & 3) 102 | *dst++ = '='; 103 | *dst = '\0'; 104 | 105 | return ret; 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simple-obfs 2 | 3 | Deprecated. Followed by [v2ray-plugin](https://github.com/shadowsocks/v2ray-plugin). 4 | 5 | ## Intro 6 | 7 | Simple-obfs is a simple obfuscating tool, designed as plugin server of shadowsocks. 8 | 9 | Current version: 0.0.5 | [Changelog](Changes) 10 | 11 | ## Build 12 | For Unix-like systems, especially Debian-based systems, 13 | e.g. Ubuntu, Debian or Linux Mint, you can build the binary like this: 14 | 15 | ```bash 16 | # Debian / Ubuntu 17 | sudo apt-get install --no-install-recommends build-essential autoconf libtool libssl-dev libpcre3-dev libev-dev asciidoc xmlto automake 18 | # CentOS / Fedora / RHEL 19 | sudo yum install gcc autoconf libtool automake make zlib-devel openssl-devel asciidoc xmlto libev-devel 20 | # Arch 21 | sudo pacman -Syu gcc autoconf libtool automake make zlib openssl asciidoc xmlto 22 | # Alpine 23 | apk add gcc autoconf make libtool automake zlib-dev openssl asciidoc xmlto libpcre32 libev-dev g++ linux-headers 24 | 25 | git clone https://github.com/shadowsocks/simple-obfs.git 26 | cd simple-obfs 27 | git submodule update --init --recursive 28 | ./autogen.sh 29 | ./configure && make 30 | sudo make install 31 | ``` 32 | ## Usage 33 | 34 | For a detailed and complete list of all supported arguments, you may refer to the 35 | man pages of the applications, respectively. 36 | 37 | ### Plugin mode with shadowsocks 38 | 39 | Add respective item to `--plugin` and `--plugin-opts` arg or as value of `plugin` and `plugin_opts` in JSON. 40 | 41 | On the client: 42 | 43 | ```bash 44 | ss-local -c config.json --plugin obfs-local --plugin-opts "obfs=http;obfs-host=www.bing.com" 45 | ``` 46 | 47 | On the server: 48 | 49 | ```bash 50 | ss-server -c config.json --plugin obfs-server --plugin-opts "obfs=http" 51 | ``` 52 | 53 | ### Standalone mode 54 | 55 | On the client: 56 | 57 | ```bash 58 | obfs-local -s server_ip -p 8139 -l 1984 --obfs http --obfs-host www.bing.com 59 | ss-local -c config.json -s 127.0.0.1 -p 1984 -l 1080 60 | ``` 61 | 62 | On the server: 63 | 64 | ```bash 65 | obfs-server -s server_ip -p 8139 --obfs http -r 127.0.0.1:8388 66 | ss-server -c config.json -s 127.0.0.1 -p 8388 67 | ``` 68 | 69 | ### Coexist with an actual Web server 70 | 71 | Only applicable on the server: 72 | 73 | ```bash 74 | # HTTP only with plugin mode 75 | ss-server -c config.json --plugin obfs-server --plugin-opts "obfs=http;failover=example.com:80" 76 | 77 | # Both HTTP and HTTPS with standalone mode 78 | obfs-server -s server_ip -p 80 --obfs http -r 127.0.0.1:8388 --failover example.com:80 79 | obfs-server -s server_ip -p 443 --obfs tls -r 127.0.0.1:8388 --failover example.com:443 80 | 81 | # suppose you have an HTTP webserver (apache/nginx/whatever) listening on localhost:8080 and HTTPS on 8443 82 | # (you probably shouldn't expose these ports) 83 | obfs-server -s server_ip -p 80 --obfs http -r 127.0.0.1:8388 --failover 127.0.0.1:8080 84 | obfs-server -s server_ip -p 443 --obfs tls -r 127.0.0.1:8388 --failover 127.0.0.1:8443 85 | ``` 86 | 87 | ## License 88 | 89 | ``` 90 | Copyright (C) 2016 Max Lv 91 | 92 | This program is free software: you can redistribute it and/or modify 93 | it under the terms of the GNU General Public License as published by 94 | the Free Software Foundation, either version 3 of the License, or 95 | (at your option) any later version. 96 | 97 | This program is distributed in the hope that it will be useful, 98 | but WITHOUT ANY WARRANTY; without even the implied warranty of 99 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 100 | GNU General Public License for more details. 101 | 102 | You should have received a copy of the GNU General Public License 103 | along with this program. If not, see . 104 | ``` 105 | -------------------------------------------------------------------------------- /src/obfs_tls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs_tls.h - Interfaces of tls obfuscating 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifndef OBFS_TLS_H 24 | #define OBFS_TLS_H 25 | 26 | #include "obfs.h" 27 | 28 | struct tls_client_hello { 29 | char content_type; 30 | short version; 31 | short len; 32 | 33 | char handshake_type; 34 | char handshake_len_1; 35 | short handshake_len_2; 36 | short handshake_version; 37 | 38 | int random_unix_time; 39 | char random_bytes[28]; 40 | char session_id_len; 41 | char session_id[32]; 42 | short cipher_suites_len; 43 | char cipher_suites[56]; 44 | char comp_methods_len; 45 | char comp_methods[1]; 46 | short ext_len; 47 | } __attribute__((packed, aligned(1))); 48 | 49 | struct tls_ext_server_name { 50 | short ext_type; 51 | short ext_len; 52 | short server_name_list_len; 53 | char server_name_type; 54 | short server_name_len; 55 | // char server_name[server_name_len]; 56 | } __attribute__((packed, aligned(1))); 57 | 58 | struct tls_ext_session_ticket { 59 | short session_ticket_type; 60 | short session_ticket_ext_len; 61 | // char session_ticket[session_ticket_ext_len]; 62 | } __attribute__((packed, aligned(1))); 63 | 64 | struct tls_ext_others { 65 | short ec_point_formats_ext_type; 66 | short ec_point_formats_ext_len; 67 | char ec_point_formats_len; 68 | char ec_point_formats[3]; 69 | 70 | short elliptic_curves_type; 71 | short elliptic_curves_ext_len; 72 | short elliptic_curves_len; 73 | char elliptic_curves[8]; 74 | 75 | short sig_algos_type; 76 | short sig_algos_ext_len; 77 | short sig_algos_len; 78 | char sig_algos[30]; 79 | 80 | short encrypt_then_mac_type; 81 | short encrypt_then_mac_ext_len; 82 | 83 | short extended_master_secret_type; 84 | short extended_master_secret_ext_len; 85 | } __attribute__((packed, aligned(1))); 86 | 87 | struct tls_server_hello { 88 | char content_type; 89 | short version; 90 | short len; 91 | 92 | char handshake_type; 93 | char handshake_len_1; 94 | short handshake_len_2; 95 | short handshake_version; 96 | 97 | int random_unix_time; 98 | char random_bytes[28]; 99 | char session_id_len; 100 | char session_id[32]; 101 | short cipher_suite; 102 | char comp_method; 103 | short ext_len; 104 | 105 | short ext_renego_info_type; 106 | short ext_renego_info_ext_len; 107 | char ext_renego_info_len; 108 | 109 | short extended_master_secret_type; 110 | short extended_master_secret_ext_len; 111 | 112 | short ec_point_formats_ext_type; 113 | short ec_point_formats_ext_len; 114 | char ec_point_formats_len; 115 | char ec_point_formats[1]; 116 | } __attribute__((packed, aligned(1))); 117 | 118 | struct tls_change_cipher_spec { 119 | char content_type; 120 | short version; 121 | short len; 122 | char msg; 123 | } __attribute__((packed, aligned(1))); 124 | 125 | struct tls_encrypted_handshake { 126 | char content_type; 127 | short version; 128 | short len; 129 | // char msg[len]; 130 | } __attribute__((packed, aligned(1))); 131 | 132 | typedef struct frame { 133 | short idx; 134 | short len; 135 | char buf[2]; 136 | } frame_t; 137 | 138 | extern obfs_para_t *obfs_tls; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /src/win32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * win32.c - Windows socket compatibility layer 3 | * 4 | * Copyright (C) 2013 - 2018, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifdef __MINGW32__ 24 | 25 | #include "win32.h" 26 | #include "utils.h" 27 | 28 | #ifndef ENABLE_QUICK_EDIT 29 | #define ENABLE_QUICK_EDIT 0x0040 30 | #endif 31 | 32 | #ifndef STD_INPUT_HANDLE 33 | #define STD_INPUT_HANDLE ((DWORD)-10) 34 | #endif 35 | 36 | static void 37 | disable_quick_edit(void) 38 | { 39 | DWORD mode = 0; 40 | HANDLE console = GetStdHandle(STD_INPUT_HANDLE); 41 | 42 | // Get current console mode 43 | if (console == NULL || !GetConsoleMode(console, &mode)) { 44 | return; 45 | } 46 | 47 | // Clear the quick edit bit in the mode flags 48 | mode &= ~ENABLE_QUICK_EDIT; 49 | mode |= ENABLE_EXTENDED_FLAGS; 50 | SetConsoleMode(console, mode); 51 | } 52 | 53 | void 54 | winsock_init(void) 55 | { 56 | int ret; 57 | WSADATA wsa_data; 58 | ret = WSAStartup(MAKEWORD(2, 2), &wsa_data); 59 | if (ret != 0) { 60 | FATAL("Failed to initialize winsock"); 61 | } 62 | // Disable quick edit mode to prevent stuck 63 | disable_quick_edit(); 64 | } 65 | 66 | void 67 | winsock_cleanup(void) 68 | { 69 | WSACleanup(); 70 | } 71 | 72 | int 73 | setnonblocking(SOCKET socket) 74 | { 75 | u_long arg = 1; 76 | return ioctlsocket(socket, FIONBIO, &arg); 77 | } 78 | 79 | void 80 | ss_error(const char *s) 81 | { 82 | char *msg = NULL; 83 | DWORD err = WSAGetLastError(); 84 | FormatMessage( 85 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 86 | FORMAT_MESSAGE_FROM_SYSTEM | 87 | FORMAT_MESSAGE_IGNORE_INSERTS, 88 | NULL, err, 89 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 90 | (LPTSTR)&msg, 0, NULL); 91 | if (msg != NULL) { 92 | // Remove trailing newline character 93 | ssize_t len = strlen(msg) - 1; 94 | if (len >= 0 && msg[len] == '\n') { 95 | msg[len] = '\0'; 96 | } 97 | LOGE("%s: [%ld] %s", s, err, msg); 98 | LocalFree(msg); 99 | } 100 | } 101 | 102 | #ifdef TCP_FASTOPEN_WINSOCK 103 | LPFN_CONNECTEX 104 | winsock_getconnectex(void) 105 | { 106 | static LPFN_CONNECTEX pConnectEx = NULL; 107 | if (pConnectEx != NULL) { 108 | return pConnectEx; 109 | } 110 | 111 | // Dummy socket for WSAIoctl 112 | SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 113 | if (s == INVALID_SOCKET) { 114 | ERROR("socket"); 115 | return NULL; 116 | } 117 | 118 | // Load ConnectEx function 119 | GUID guid = WSAID_CONNECTEX; 120 | DWORD numBytes; 121 | int ret = -1; 122 | ret = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, 123 | (void *)&guid, sizeof(guid), 124 | (void *)&pConnectEx, sizeof(pConnectEx), 125 | &numBytes, NULL, NULL); 126 | if (ret != 0) { 127 | ERROR("WSAIoctl"); 128 | closesocket(s); 129 | return NULL; 130 | } 131 | closesocket(s); 132 | return pConnectEx; 133 | } 134 | 135 | int 136 | winsock_dummybind(SOCKET fd, struct sockaddr *sa) 137 | { 138 | struct sockaddr_storage ss; 139 | memset(&ss, 0, sizeof(ss)); 140 | if (sa->sa_family == AF_INET) { 141 | struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 142 | sin->sin_family = AF_INET; 143 | sin->sin_addr.s_addr = INADDR_ANY; 144 | } else if (sa->sa_family == AF_INET6) { 145 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 146 | sin6->sin6_family = AF_INET6; 147 | sin6->sin6_addr = in6addr_any; 148 | } else { 149 | return -1; 150 | } 151 | if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 && 152 | WSAGetLastError() != WSAEINVAL) { 153 | return -1; 154 | } 155 | return 0; 156 | } 157 | #endif 158 | 159 | #endif // __MINGW32__ 160 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl -*- Autoconf -*- 2 | dnl Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.67]) 5 | AC_INIT([simple-obfs], [0.0.5], [max.c.lv@gmail.com]) 6 | AC_CONFIG_SRCDIR([src/encrypt.c]) 7 | AC_CONFIG_HEADERS([config.h]) 8 | AC_CONFIG_AUX_DIR(auto) 9 | AC_CONFIG_MACRO_DIR([m4]) 10 | AC_USE_SYSTEM_EXTENSIONS 11 | 12 | AM_INIT_AUTOMAKE([subdir-objects foreign -Wno-gnu -Werror]) 13 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 14 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 15 | AM_MAINTAINER_MODE 16 | AM_DEP_TRACK 17 | 18 | dnl Checks for lib 19 | AC_DISABLE_STATIC 20 | AC_DISABLE_SHARED 21 | LT_INIT([dlopen]) 22 | 23 | AC_ARG_ENABLE([documentation], 24 | AS_HELP_STRING([--disable-documentation], [do not build documentation]), 25 | [disable_documentation=true], 26 | [disable_documentation=false]) 27 | AM_CONDITIONAL([ENABLE_DOCUMENTATION], [test x$disable_documentation = xfalse]) 28 | 29 | AM_COND_IF([ENABLE_DOCUMENTATION], [ 30 | AC_PATH_PROG([ASCIIDOC], [asciidoc]) 31 | test x"${ASCIIDOC}" != x || AC_MSG_ERROR([Cannot find `asciidoc` in PATH.]) 32 | AC_PATH_PROG([XMLTO], [xmlto]) 33 | test x"$XMLTO" != x || AC_MSG_ERROR([Cannot find `xmlto` in PATH.]) 34 | AC_PATH_PROG([GZIP], [gzip], [gzip]) 35 | AC_PATH_PROG([MV], [mv], [mv]) 36 | AC_PROG_SED 37 | ]) 38 | 39 | dnl Checks for programs. 40 | AC_PROG_CC 41 | AM_PROG_CC_C_O 42 | AC_PROG_INSTALL 43 | AC_PROG_LN_S 44 | AC_PROG_LIBTOOL 45 | AC_PROG_MAKE_SET 46 | AC_LANG_SOURCE 47 | 48 | dnl Add library for mingw 49 | case $host in 50 | *-mingw*) 51 | CFLAGS="$CFLAGS -mno-ms-bitfields" 52 | LIBS="$LIBS -lws2_32" 53 | ;; 54 | *-cygwin*) 55 | CFLAGS="$CFLAGS -mno-ms-bitfields" 56 | ;; 57 | *) 58 | ;; 59 | esac 60 | 61 | dnl Checks for TLS 62 | AX_TLS([:], [:]) 63 | 64 | dnl Checks for inet_ntop 65 | ss_FUNC_INET_NTOP 66 | 67 | dnl Checks for host. 68 | AC_MSG_CHECKING(for what kind of host) 69 | case $host in 70 | *-linux*) 71 | os_support=linux 72 | AC_MSG_RESULT(Linux) 73 | ;; 74 | *-mingw*) 75 | os_support=mingw 76 | AC_MSG_RESULT(MinGW) 77 | ;; 78 | *) 79 | AC_MSG_RESULT(transparent proxy does not support for $host) 80 | ;; 81 | esac 82 | 83 | dnl Checks for stack protector 84 | GGL_CHECK_STACK_PROTECTOR([has_stack_protector=yes], [has_stack_protector=no]) 85 | # XXX - disable -fstack-protector due to missing libssp_nonshared 86 | case "$host_os" in 87 | *aix*) 88 | AC_MSG_NOTICE([-fstack-protector disabled on AIX]) 89 | has_stack_protector=no 90 | ;; 91 | *sunos*) 92 | AC_MSG_NOTICE([-fstack-protector disabled on SunOS]) 93 | has_stack_protector=no 94 | ;; 95 | *solaris*) 96 | AC_MSG_NOTICE([-fstack-protector disabled on Solaris]) 97 | has_stack_protector=no 98 | ;; 99 | esac 100 | 101 | AC_ARG_ENABLE(ssp, 102 | [AS_HELP_STRING(--disable-ssp,Do not compile with -fstack-protector)], 103 | [ 104 | enable_ssp="no" 105 | ], 106 | [ 107 | enable_ssp="yes" 108 | ]) 109 | 110 | if test x$has_stack_protector = xyes && test x$enable_ssp = xyes; then 111 | CFLAGS="$CFLAGS -fstack-protector" 112 | AC_MSG_NOTICE([-fstack-protector enabled in CFLAGS]) 113 | fi 114 | 115 | AM_CONDITIONAL(BUILD_REDIRECTOR, test "$os_support" = "linux") 116 | AM_CONDITIONAL(BUILD_WINCOMPAT, test "$os_support" = "mingw") 117 | 118 | dnl Checks for header files. 119 | AC_CHECK_HEADERS([limits.h stdint.h inttypes.h arpa/inet.h fcntl.h langinfo.h locale.h netdb.h netinet/in.h stdlib.h string.h strings.h unistd.h sys/ioctl.h]) 120 | 121 | dnl A special check required for on Darwin. See 122 | dnl http://www.gnu.org/software/autoconf/manual/html_node/Header-Portability.html. 123 | AC_CHECK_HEADERS([sys/socket.h]) 124 | AC_CHECK_HEADERS([net/if.h], [], [], 125 | [ 126 | #include 127 | #ifdef STDC_HEADERS 128 | # include 129 | # include 130 | #else 131 | # ifdef HAVE_STDLIB_H 132 | # include 133 | # endif 134 | #endif 135 | #ifdef HAVE_SYS_SOCKET_H 136 | # include 137 | #endif 138 | ]) 139 | 140 | case $host in 141 | *-mingw*) 142 | AC_DEFINE([CONNECT_IN_PROGRESS], [WSAEWOULDBLOCK], [errno for incomplete non-blocking connect(2)]) 143 | AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h mswsock.h], [], [AC_MSG_ERROR([Missing MinGW headers])], []) 144 | ;; 145 | *-linux*) 146 | AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)]) 147 | dnl Checks for netfilter headers 148 | AC_CHECK_HEADERS([linux/if.h linux/netfilter_ipv4.h linux/netfilter_ipv6/ip6_tables.h], 149 | [], [AC_MSG_ERROR([Missing netfilter headers])], 150 | [[ 151 | #if HAVE_LIMITS_H 152 | #include 153 | #endif 154 | /* Netfilter ip(6)tables v1.4.0 has broken headers */ 155 | #if HAVE_NETINET_IN_H 156 | #include 157 | #endif 158 | #if HAVE_LINUX_IF_H 159 | #include 160 | #endif 161 | #if HAVE_SYS_SOCKET_H 162 | #include 163 | #endif 164 | ]]) 165 | ;; 166 | *) 167 | # These are POSIX-like systems using BSD-like sockets API. 168 | AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)]) 169 | ;; 170 | esac 171 | 172 | AC_C_BIGENDIAN 173 | 174 | dnl Checks for typedefs, structures, and compiler characteristics. 175 | AC_C_INLINE 176 | AC_TYPE_SSIZE_T 177 | 178 | dnl Checks for header files. 179 | AC_HEADER_ASSERT 180 | AC_HEADER_STDC 181 | AC_HEADER_SYS_WAIT 182 | 183 | dnl Checks for typedefs, structures, and compiler characteristics. 184 | AC_C_CONST 185 | AC_TYPE_PID_T 186 | AC_TYPE_SIZE_T 187 | AC_TYPE_SSIZE_T 188 | AC_TYPE_UINT16_T 189 | AC_TYPE_UINT8_T 190 | AC_HEADER_TIME 191 | 192 | dnl Checks for library functions. 193 | AC_FUNC_FORK 194 | AC_FUNC_SELECT_ARGTYPES 195 | AC_TYPE_SIGNAL 196 | AC_CHECK_FUNCS([memset select setresuid setreuid strerror getpwnam_r setrlimit]) 197 | 198 | AC_CHECK_LIB(socket, connect) 199 | 200 | dnl Checks for library functions. 201 | AC_CHECK_FUNCS([malloc memset socket]) 202 | 203 | AC_ARG_WITH(ev, 204 | AS_HELP_STRING([--with-ev=DIR], [use a specific libev library]), 205 | [CFLAGS="$CFLAGS -I$withval/include" 206 | CPPFLAGS="$CPPFLAGS -I$withval/include" 207 | LDFLAGS="$LDFLAGS -L$withval/lib"] 208 | ) 209 | AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])]) 210 | 211 | AM_COND_IF([ENABLE_DOCUMENTATION], 212 | [AC_CONFIG_FILES([doc/Makefile]) 213 | ]) 214 | 215 | AC_CONFIG_FILES([Makefile 216 | libcork/Makefile 217 | src/Makefile]) 218 | 219 | AC_OUTPUT 220 | -------------------------------------------------------------------------------- /src/json.h: -------------------------------------------------------------------------------- 1 | 2 | /* vim: set et ts=3 sw=3 sts=3 ft=c: 3 | * 4 | * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. 5 | * https://github.com/udp/json-parser 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _JSON_H 32 | #define _JSON_H 33 | 34 | #ifndef json_char 35 | #define json_char char 36 | #endif 37 | 38 | #ifndef json_int_t 39 | #ifndef _MSC_VER 40 | #include 41 | #define json_int_t int64_t 42 | #else 43 | #define json_int_t __int64 44 | #endif 45 | #endif 46 | 47 | #include 48 | 49 | #ifdef __cplusplus 50 | 51 | #include 52 | 53 | extern "C" 54 | { 55 | 56 | #endif 57 | 58 | typedef struct 59 | { 60 | unsigned long max_memory; 61 | int settings; 62 | 63 | /* Custom allocator support (leave null to use malloc/free) 64 | */ 65 | 66 | void * (* mem_alloc) (size_t, int zero, void * user_data); 67 | void (* mem_free) (void *, void * user_data); 68 | 69 | void * user_data; /* will be passed to mem_alloc and mem_free */ 70 | 71 | size_t value_extra; /* how much extra space to allocate for values? */ 72 | 73 | } json_settings; 74 | 75 | #define json_enable_comments 0x01 76 | 77 | typedef enum 78 | { 79 | json_none, 80 | json_object, 81 | json_array, 82 | json_integer, 83 | json_double, 84 | json_string, 85 | json_boolean, 86 | json_null 87 | 88 | } json_type; 89 | 90 | extern const struct _json_value json_value_none; 91 | 92 | typedef struct _json_object_entry 93 | { 94 | json_char * name; 95 | unsigned int name_length; 96 | 97 | struct _json_value * value; 98 | 99 | } json_object_entry; 100 | 101 | typedef struct _json_value 102 | { 103 | struct _json_value * parent; 104 | 105 | json_type type; 106 | 107 | union 108 | { 109 | int boolean; 110 | json_int_t integer; 111 | double dbl; 112 | 113 | struct 114 | { 115 | unsigned int length; 116 | json_char * ptr; /* null terminated */ 117 | 118 | } string; 119 | 120 | struct 121 | { 122 | unsigned int length; 123 | 124 | json_object_entry * values; 125 | 126 | #if defined(__cplusplus) && __cplusplus >= 201103L 127 | decltype(values) begin () const 128 | { return values; 129 | } 130 | decltype(values) end () const 131 | { return values + length; 132 | } 133 | #endif 134 | 135 | } object; 136 | 137 | struct 138 | { 139 | unsigned int length; 140 | struct _json_value ** values; 141 | 142 | #if defined(__cplusplus) && __cplusplus >= 201103L 143 | decltype(values) begin () const 144 | { return values; 145 | } 146 | decltype(values) end () const 147 | { return values + length; 148 | } 149 | #endif 150 | 151 | } array; 152 | 153 | } u; 154 | 155 | union 156 | { 157 | struct _json_value * next_alloc; 158 | void * object_mem; 159 | 160 | } _reserved; 161 | 162 | #ifdef JSON_TRACK_SOURCE 163 | 164 | /* Location of the value in the source JSON 165 | */ 166 | unsigned int line, col; 167 | 168 | #endif 169 | 170 | 171 | /* Some C++ operator sugar */ 172 | 173 | #ifdef __cplusplus 174 | 175 | public: 176 | 177 | inline _json_value () 178 | { memset (this, 0, sizeof (_json_value)); 179 | } 180 | 181 | inline const struct _json_value &operator [] (int index) const 182 | { 183 | if (type != json_array || index < 0 184 | || ((unsigned int) index) >= u.array.length) 185 | { 186 | return json_value_none; 187 | } 188 | 189 | return *u.array.values [index]; 190 | } 191 | 192 | inline const struct _json_value &operator [] (const char * index) const 193 | { 194 | if (type != json_object) 195 | return json_value_none; 196 | 197 | for (unsigned int i = 0; i < u.object.length; ++ i) 198 | if (!strcmp (u.object.values [i].name, index)) 199 | return *u.object.values [i].value; 200 | 201 | return json_value_none; 202 | } 203 | 204 | inline operator const char * () const 205 | { 206 | switch (type) 207 | { 208 | case json_string: 209 | return u.string.ptr; 210 | 211 | default: 212 | return ""; 213 | }; 214 | } 215 | 216 | inline operator json_int_t () const 217 | { 218 | switch (type) 219 | { 220 | case json_integer: 221 | return u.integer; 222 | 223 | case json_double: 224 | return (json_int_t) u.dbl; 225 | 226 | default: 227 | return 0; 228 | }; 229 | } 230 | 231 | inline operator bool () const 232 | { 233 | if (type != json_boolean) 234 | return false; 235 | 236 | return u.boolean != 0; 237 | } 238 | 239 | inline operator double () const 240 | { 241 | switch (type) 242 | { 243 | case json_integer: 244 | return (double) u.integer; 245 | 246 | case json_double: 247 | return u.dbl; 248 | 249 | default: 250 | return 0; 251 | }; 252 | } 253 | 254 | #endif 255 | 256 | } json_value; 257 | 258 | json_value * json_parse (const json_char * json, 259 | size_t length); 260 | 261 | #define json_error_max 128 262 | json_value * json_parse_ex (json_settings * settings, 263 | const json_char * json, 264 | size_t length, 265 | char * error); 266 | 267 | void json_value_free (json_value *); 268 | 269 | 270 | /* Not usually necessary, unless you used a custom mem_alloc and now want to 271 | * use a custom mem_free. 272 | */ 273 | void json_value_free_ex (json_settings * settings, 274 | json_value *); 275 | 276 | 277 | #ifdef __cplusplus 278 | } /* extern "C" */ 279 | #endif 280 | 281 | #endif 282 | 283 | 284 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: simple-obfs 3 | Upstream-Contact: Max Lv 4 | Source: https://github.com/shadowsocks/simple-obfs 5 | 6 | Files: * 7 | Copyright: 2013-2017 Max Lv 8 | 2014 Linus Yang 9 | License: GPL-3+ 10 | 11 | Files: debian/* 12 | Copyright: 2017 Roger Shimizu 13 | License: GPL-3+ 14 | 15 | Files: m4/ax_tls.m4 16 | Copyright: 2008 Alan Woodland 17 | 2010 Diego Elio Petteno` 18 | License: GPL-3+ with Autoconf exception 19 | 20 | Files: m4/stack-protector.m4 21 | Copyright: 2007 Google Inc. 22 | License: Apache-2.0 23 | 24 | Files: src/base64.c src/base64.h 25 | Copyright: 2006 Ryan Martell 26 | License: LGPL-2.1+ 27 | 28 | Files: src/json.c src/json.h 29 | Copyright: 2012-2014 James McLaughlin et al. 30 | License: BSD-2-Clause 31 | 32 | Files: m4/inet_ntop.m4 33 | Copyright: 2005-2013, Free Software Foundation, Inc 34 | License: FSFULLR 35 | Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc. 36 | This file is free software; the Free Software Foundation 37 | gives unlimited permission to copy and/or distribute it, 38 | with or without modifications, as long as this notice is preserved. 39 | 40 | Files: src/uthash.h 41 | Copyright: 2003-2016, Troy D. Hanson 42 | License: BSD-1-clause 43 | Redistribution and use in source and binary forms, with or without 44 | modification, are permitted provided that the following conditions are met: 45 | . 46 | * Redistributions of source code must retain the above copyright 47 | notice, this list of conditions and the following disclaimer. 48 | . 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 50 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 52 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 53 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 54 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 55 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 56 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 57 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 58 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 59 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 | 61 | License: Apache-2.0 62 | Licensed under the Apache License, Version 2.0 (the "License"); 63 | you may not use this file except in compliance with the License. 64 | You may obtain a copy of the License at 65 | . 66 | http://www.apache.org/licenses/LICENSE-2.0 67 | . 68 | Unless required by applicable law or agreed to in writing, software 69 | distributed under the License is distributed on an "AS IS" BASIS, 70 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 71 | See the License for the specific language governing permissions and 72 | limitations under the License. 73 | . 74 | On Debian systems, the complete text of the Apache License Version 2.0 75 | can be found in `/usr/share/common-licenses/Apache-2.0'. 76 | 77 | License: BSD-2-Clause 78 | Redistribution and use in source and binary forms, with or without 79 | modification, are permitted provided that the following conditions 80 | are met: 81 | . 82 | 1. Redistributions of source code must retain the above copyright 83 | notice, this list of conditions and the following disclaimer. 84 | . 85 | 2. Redistributions in binary form must reproduce the above copyright 86 | notice, this list of conditions and the following disclaimer in the 87 | documentation and/or other materials provided with the distribution. 88 | . 89 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 90 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 91 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 92 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 93 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 94 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 95 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 96 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 97 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 98 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 99 | SUCH DAMAGE. 100 | 101 | License: GPL-3+ 102 | This file is part of the simple-obfs. 103 | . 104 | simple-obfs is free software; you can redistribute it and/or modify 105 | it under the terms of the GNU General Public License as published by 106 | the Free Software Foundation; either version 3 of the License, or 107 | (at your option) any later version. 108 | . 109 | simple-obfs is distributed in the hope that it will be useful, 110 | but WITHOUT ANY WARRANTY; without even the implied warranty of 111 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 112 | GNU General Public License for more details. 113 | . 114 | You should have received a copy of the GNU General Public License 115 | along with simple-obfs; see the file COPYING. If not, see 116 | . 117 | . 118 | On Debian systems, the complete text of the GNU General Public License 119 | Version 3 can be found in `/usr/share/common-licenses/GPL-3'. 120 | 121 | License: GPL-3+ with Autoconf exception 122 | This program is free software: you can redistribute it and/or modify it 123 | under the terms of the GNU General Public License as published by the 124 | Free Software Foundation, either version 3 of the License, or (at your 125 | option) any later version. 126 | . 127 | This program is distributed in the hope that it will be useful, but 128 | WITHOUT ANY WARRANTY; without even the implied warranty of 129 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 130 | Public License for more details. 131 | . 132 | You should have received a copy of the GNU General Public License along 133 | with this program. If not, see . 134 | . 135 | As a special exception, the respective Autoconf Macro's copyright owner 136 | gives unlimited permission to copy, distribute and modify the configure 137 | scripts that are the output of Autoconf when processing the Macro. You 138 | need not follow the terms of the GNU General Public License when using 139 | or distributing such scripts, even though portions of the text of the 140 | Macro appear in them. The GNU General Public License (GPL) does govern 141 | all other use of the material that constitutes the Autoconf Macro. 142 | . 143 | This special exception to the GPL applies to versions of the Autoconf 144 | Macro released by the Autoconf Archive. When you make and distribute a 145 | modified version of the Autoconf Macro, you may extend this special 146 | exception to the GPL to apply to your modified version as well. 147 | 148 | License: LGPL-2.1+ 149 | This file is part of FFmpeg. 150 | . 151 | FFmpeg is free software; you can redistribute it and/or 152 | modify it under the terms of the GNU Lesser General Public 153 | License as published by the Free Software Foundation; either 154 | version 2.1 of the License, or (at your option) any later version. 155 | . 156 | FFmpeg is distributed in the hope that it will be useful, 157 | but WITHOUT ANY WARRANTY; without even the implied warranty of 158 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 159 | Lesser General Public License for more details. 160 | . 161 | You should have received a copy of the GNU Lesser General Public 162 | License along with FFmpeg; if not, write to the Free Software 163 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 164 | -------------------------------------------------------------------------------- /src/jconf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * jconf.c - Parse the JSON format config file 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * simple-obfs is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * simple-obfs is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with simple-obfs; see the file COPYING. If not, see 19 | * . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "utils.h" 29 | #include "jconf.h" 30 | #include "json.h" 31 | #include "string.h" 32 | 33 | #include 34 | 35 | #define check_json_value_type(value, expected_type, message) \ 36 | do { \ 37 | if ((value)->type != (expected_type)) \ 38 | FATAL((message)); \ 39 | } while(0) 40 | 41 | static char * 42 | to_string(const json_value *value) 43 | { 44 | if (value->type == json_string) { 45 | return ss_strndup(value->u.string.ptr, value->u.string.length); 46 | } else if (value->type == json_integer) { 47 | return strdup(ss_itoa(value->u.integer)); 48 | } else if (value->type == json_null) { 49 | return "null"; 50 | } else { 51 | LOGE("%d", value->type); 52 | FATAL("Invalid config format."); 53 | } 54 | return 0; 55 | } 56 | 57 | void 58 | free_addr(ss_addr_t *addr) 59 | { 60 | ss_free(addr->host); 61 | ss_free(addr->port); 62 | } 63 | 64 | void 65 | parse_addr(const char *str, ss_addr_t *addr) 66 | { 67 | int ipv6 = 0, ret = -1, n = 0; 68 | char *pch; 69 | 70 | struct cork_ip ip; 71 | if (cork_ip_init(&ip, str) != -1) { 72 | addr->host = strdup(str); 73 | addr->port = NULL; 74 | return; 75 | } 76 | 77 | pch = strchr(str, ':'); 78 | while (pch != NULL) { 79 | n++; 80 | ret = pch - str; 81 | pch = strchr(pch + 1, ':'); 82 | } 83 | if (n > 1) { 84 | ipv6 = 1; 85 | if (str[ret - 1] != ']') { 86 | ret = -1; 87 | } 88 | } 89 | 90 | if (ret == -1) { 91 | if (ipv6) { 92 | addr->host = ss_strndup(str + 1, strlen(str) - 2); 93 | } else { 94 | addr->host = strdup(str); 95 | } 96 | addr->port = NULL; 97 | } else { 98 | if (ipv6) { 99 | addr->host = ss_strndup(str + 1, ret - 2); 100 | } else { 101 | addr->host = ss_strndup(str, ret); 102 | } 103 | addr->port = strdup(str + ret + 1); 104 | } 105 | } 106 | 107 | jconf_t * 108 | read_jconf(const char *file) 109 | { 110 | static jconf_t conf; 111 | 112 | memset(&conf, 0, sizeof(jconf_t)); 113 | 114 | char *buf; 115 | json_value *obj; 116 | 117 | FILE *f = fopen(file, "rb"); 118 | if (f == NULL) { 119 | FATAL("Invalid config path."); 120 | } 121 | 122 | fseek(f, 0, SEEK_END); 123 | long pos = ftell(f); 124 | fseek(f, 0, SEEK_SET); 125 | 126 | if (pos >= MAX_CONF_SIZE) { 127 | FATAL("Too large config file."); 128 | } 129 | 130 | buf = ss_malloc(pos + 1); 131 | if (buf == NULL) { 132 | FATAL("No enough memory."); 133 | } 134 | 135 | int nread = fread(buf, pos, 1, f); 136 | if (!nread) { 137 | FATAL("Failed to read the config file."); 138 | } 139 | fclose(f); 140 | 141 | buf[pos] = '\0'; // end of string 142 | 143 | json_settings settings = { 0UL, 0, NULL, NULL, NULL }; 144 | char error_buf[512]; 145 | obj = json_parse_ex(&settings, buf, pos, error_buf); 146 | 147 | if (obj == NULL) { 148 | FATAL(error_buf); 149 | } 150 | 151 | if (obj->type == json_object) { 152 | unsigned int i, j; 153 | for (i = 0; i < obj->u.object.length; i++) { 154 | char *name = obj->u.object.values[i].name; 155 | json_value *value = obj->u.object.values[i].value; 156 | if (strcmp(name, "server") == 0) { 157 | if (value->type == json_array) { 158 | for (j = 0; j < value->u.array.length; j++) { 159 | if (j >= MAX_REMOTE_NUM) { 160 | break; 161 | } 162 | json_value *v = value->u.array.values[j]; 163 | char *addr_str = to_string(v); 164 | parse_addr(addr_str, conf.remote_addr + j); 165 | ss_free(addr_str); 166 | conf.remote_num = j + 1; 167 | } 168 | } else if (value->type == json_string) { 169 | conf.remote_addr[0].host = to_string(value); 170 | conf.remote_addr[0].port = NULL; 171 | conf.remote_num = 1; 172 | } 173 | } else if (strcmp(name, "server_port") == 0) { 174 | conf.remote_port = to_string(value); 175 | } else if (strcmp(name, "local_address") == 0) { 176 | conf.local_addr = to_string(value); 177 | } else if (strcmp(name, "local_port") == 0) { 178 | conf.local_port = to_string(value); 179 | } else if (strcmp(name, "timeout") == 0) { 180 | conf.timeout = to_string(value); 181 | } else if (strcmp(name, "user") == 0) { 182 | conf.user = to_string(value); 183 | } else if (strcmp(name, "obfs") == 0) { 184 | conf.obfs = to_string(value); 185 | } else if (strcmp(name, "obfs_host") == 0) { 186 | conf.obfs_host = to_string(value); 187 | } else if (strcmp(name, "obfs_uri") == 0) { 188 | conf.obfs_uri = to_string(value); 189 | } else if (strcmp(name, "http_method") == 0) { 190 | conf.http_method = to_string(value); 191 | } else if (strcmp(name, "failover") == 0) { 192 | conf.failover = to_string(value); 193 | } else if (strcmp(name, "fast_open") == 0) { 194 | check_json_value_type(value, json_boolean, 195 | "invalid config file: option 'fast_open' must be a boolean"); 196 | conf.fast_open = value->u.boolean; 197 | } else if (strcmp(name, "nofile") == 0) { 198 | check_json_value_type(value, json_integer, 199 | "invalid config file: option 'nofile' must be an integer"); 200 | conf.nofile = value->u.integer; 201 | } else if (strcmp(name, "nameserver") == 0) { 202 | conf.nameserver = to_string(value); 203 | } else if (strcmp(name, "dst_addr") == 0) { 204 | conf.dst_addr = to_string(value); 205 | } else if (strcmp(name, "mptcp") == 0) { 206 | check_json_value_type(value, json_boolean, 207 | "invalid config file: option 'mptcp' must be a boolean"); 208 | conf.mptcp = value->u.boolean; 209 | } else if (strcmp(name, "ipv6_first") == 0) { 210 | check_json_value_type(value, json_boolean, 211 | "invalid config file: option 'ipv6_first' must be a boolean"); 212 | conf.ipv6_first = value->u.boolean; 213 | } else if (strcmp(name, "reverse_proxy") == 0) { 214 | check_json_value_type(value, json_boolean, 215 | "invalid config file: option 'reverse_proxy' must be a boolean"); 216 | conf.reverse_proxy = value->u.boolean; 217 | } 218 | } 219 | } else { 220 | FATAL("Invalid config file"); 221 | } 222 | 223 | ss_free(buf); 224 | json_value_free(obj); 225 | return &conf; 226 | } 227 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.h - Misc utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #if defined(USE_CRYPTO_OPENSSL) 24 | 25 | #include 26 | #define USING_CRYPTO OPENSSL_VERSION_TEXT 27 | 28 | #elif defined(USE_CRYPTO_POLARSSL) 29 | #include 30 | #define USING_CRYPTO POLARSSL_VERSION_STRING_FULL 31 | 32 | #elif defined(USE_CRYPTO_MBEDTLS) 33 | #include 34 | #define USING_CRYPTO MBEDTLS_VERSION_STRING_FULL 35 | 36 | #endif 37 | 38 | #ifndef _UTILS_H 39 | #define _UTILS_H 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #define PORTSTRLEN 16 47 | #define SS_ADDRSTRLEN (INET6_ADDRSTRLEN + PORTSTRLEN + 1) 48 | 49 | #ifdef ANDROID 50 | 51 | #include 52 | 53 | #define USE_TTY() 54 | #define USE_SYSLOG(ident) 55 | #define LOGI(...) \ 56 | ((void)__android_log_print(ANDROID_LOG_DEBUG, "simple-obfs", \ 57 | __VA_ARGS__)) 58 | #define LOGE(...) \ 59 | ((void)__android_log_print(ANDROID_LOG_ERROR, "simple-obfs", \ 60 | __VA_ARGS__)) 61 | 62 | #else 63 | 64 | #define STR(x) # x 65 | #define TOSTR(x) STR(x) 66 | 67 | #ifdef LIB_ONLY 68 | 69 | extern FILE *logfile; 70 | 71 | #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" 72 | 73 | #define USE_TTY() 74 | 75 | #define USE_SYSLOG(ident) 76 | 77 | #define USE_LOGFILE(ident) \ 78 | do { \ 79 | if (ident != NULL) { logfile = fopen(ident, "w+"); } } \ 80 | while (0) 81 | 82 | #define CLOSE_LOGFILE \ 83 | do { \ 84 | if (logfile != NULL) { fclose(logfile); } } \ 85 | while (0) 86 | 87 | #define LOGI(format, ...) \ 88 | do { \ 89 | if (logfile != NULL) { \ 90 | time_t now = time(NULL); \ 91 | char timestr[20]; \ 92 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 93 | fprintf(logfile, " %s [simple-obfs] INFO: " format "\n", timestr, ## __VA_ARGS__); \ 94 | fflush(logfile); } \ 95 | } \ 96 | while (0) 97 | 98 | #define LOGE(format, ...) \ 99 | do { \ 100 | if (logfile != NULL) { \ 101 | time_t now = time(NULL); \ 102 | char timestr[20]; \ 103 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 104 | fprintf(logfile, " %s [simple-obfs] ERROR: " format "\n", timestr, \ 105 | ## __VA_ARGS__); \ 106 | fflush(logfile); } \ 107 | } \ 108 | while (0) 109 | 110 | #elif defined(_WIN32) 111 | 112 | #define TIME_FORMAT "%Y-%m-%d %H:%M:%S" 113 | 114 | #define USE_TTY() 115 | 116 | #define USE_SYSLOG(ident) 117 | 118 | #define LOGI(format, ...) \ 119 | do { \ 120 | time_t now = time(NULL); \ 121 | char timestr[20]; \ 122 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 123 | fprintf(stderr, " %s [simple-obfs] INFO: " format "\n", timestr, ## __VA_ARGS__); \ 124 | fflush(stderr); } \ 125 | while (0) 126 | 127 | #define LOGE(format, ...) \ 128 | do { \ 129 | time_t now = time(NULL); \ 130 | char timestr[20]; \ 131 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 132 | fprintf(stderr, " %s [simple-obfs] ERROR: " format "\n", timestr, ## __VA_ARGS__); \ 133 | fflush(stderr); } \ 134 | while (0) 135 | 136 | #else 137 | 138 | #include 139 | 140 | extern int use_tty; 141 | #define USE_TTY() \ 142 | do { \ 143 | use_tty = isatty(STDERR_FILENO); \ 144 | } while (0) \ 145 | 146 | #define HAS_SYSLOG 147 | extern int use_syslog; 148 | 149 | #define TIME_FORMAT "%F %T" 150 | 151 | #define USE_SYSLOG(ident) \ 152 | do { \ 153 | use_syslog = 1; \ 154 | openlog((ident), LOG_CONS | LOG_PID, 0); } \ 155 | while (0) 156 | 157 | #define LOGI(format, ...) \ 158 | do { \ 159 | if (use_syslog) { \ 160 | syslog(LOG_INFO, format, ## __VA_ARGS__); \ 161 | } else { \ 162 | time_t now = time(NULL); \ 163 | char timestr[20]; \ 164 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 165 | if (use_tty) { \ 166 | fprintf(stderr, "\e[01;32m %s [simple-obfs] INFO: \e[0m" format "\n", timestr, \ 167 | ## __VA_ARGS__); \ 168 | } else { \ 169 | fprintf(stderr, " %s [simple-obfs] INFO: " format "\n", timestr, \ 170 | ## __VA_ARGS__); \ 171 | } \ 172 | } \ 173 | } \ 174 | while (0) 175 | 176 | #define LOGE(format, ...) \ 177 | do { \ 178 | if (use_syslog) { \ 179 | syslog(LOG_ERR, format, ## __VA_ARGS__); \ 180 | } else { \ 181 | time_t now = time(NULL); \ 182 | char timestr[20]; \ 183 | strftime(timestr, 20, TIME_FORMAT, localtime(&now)); \ 184 | if (use_tty) { \ 185 | fprintf(stderr, "\e[01;35m %s [simple-obfs] ERROR: \e[0m" format "\n", timestr, \ 186 | ## __VA_ARGS__); \ 187 | } else { \ 188 | fprintf(stderr, " %s [simple-obfs] ERROR: " format "\n", timestr, \ 189 | ## __VA_ARGS__); \ 190 | } \ 191 | } } \ 192 | while (0) 193 | 194 | #endif 195 | /* _WIN32 */ 196 | 197 | #endif 198 | 199 | #ifdef __MINGW32__ 200 | 201 | #ifdef ERROR 202 | #undef ERROR 203 | #endif 204 | #define ERROR(s) ss_error(s) 205 | void ss_error(const char *s); // Implemented in win32.c 206 | 207 | #else 208 | 209 | void ERROR(const char *s); 210 | 211 | #endif 212 | 213 | char *ss_itoa(int i); 214 | int ss_isnumeric(const char *s); 215 | int run_as(const char *user); 216 | void FATAL(const char *msg); 217 | void usage(void); 218 | void daemonize(const char *path); 219 | char *ss_strndup(const char *s, size_t n); 220 | #ifdef HAVE_SETRLIMIT 221 | int set_nofile(int nofile); 222 | #endif 223 | 224 | void *ss_malloc(size_t size); 225 | void *ss_realloc(void *ptr, size_t new_size); 226 | 227 | #define ss_free(ptr) \ 228 | do { \ 229 | free(ptr); \ 230 | ptr = NULL; \ 231 | } while (0) 232 | 233 | #endif // _UTILS_H 234 | -------------------------------------------------------------------------------- /src/obfs_http.c: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs_http.c - Implementation of http obfuscating 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include /* isblank() */ 29 | 30 | #include "base64.h" 31 | #include "utils.h" 32 | #include "obfs_http.h" 33 | 34 | static const char *http_request_template = 35 | "%s %s HTTP/1.1\r\n" 36 | "Host: %s\r\n" 37 | "User-Agent: curl/7.%d.%d\r\n" 38 | "Upgrade: websocket\r\n" 39 | "Connection: Upgrade\r\n" 40 | "Sec-WebSocket-Key: %s\r\n" 41 | "Content-Length: %lu\r\n" 42 | "\r\n"; 43 | 44 | static const char *http_response_template = 45 | "HTTP/1.1 101 Switching Protocols\r\n" 46 | "Server: nginx/1.%d.%d\r\n" 47 | "Date: %s\r\n" 48 | "Upgrade: websocket\r\n" 49 | "Connection: Upgrade\r\n" 50 | "Sec-WebSocket-Accept: %s\r\n" 51 | "\r\n"; 52 | 53 | static int obfs_http_request(buffer_t *, size_t, obfs_t *); 54 | static int obfs_http_response(buffer_t *, size_t, obfs_t *); 55 | static int deobfs_http_header(buffer_t *, size_t, obfs_t *); 56 | static int check_http_header(buffer_t *buf); 57 | static void disable_http(obfs_t *obfs); 58 | static int is_enable_http(obfs_t *obfs); 59 | 60 | static int get_header(const char *, const char *, int, char **); 61 | static int next_header(const char **, int *); 62 | 63 | static obfs_para_t obfs_http_st = { 64 | .name = "http", 65 | .port = 80, 66 | .send_empty_response_upon_connection = true, 67 | 68 | .obfs_request = &obfs_http_request, 69 | .obfs_response = &obfs_http_response, 70 | .deobfs_request = &deobfs_http_header, 71 | .deobfs_response = &deobfs_http_header, 72 | .check_obfs = &check_http_header, 73 | .disable = &disable_http, 74 | .is_enable = &is_enable_http 75 | }; 76 | 77 | obfs_para_t *obfs_http = &obfs_http_st; 78 | 79 | static int 80 | obfs_http_request(buffer_t *buf, size_t cap, obfs_t *obfs) 81 | { 82 | 83 | if (obfs == NULL || obfs->obfs_stage != 0) return 0; 84 | obfs->obfs_stage++; 85 | 86 | static int major_version = 0; 87 | static int minor_version = 0; 88 | 89 | major_version = major_version ? major_version : rand() % 51; 90 | minor_version = minor_version ? minor_version : rand() % 2; 91 | 92 | char host_port[256]; 93 | char http_header[512]; 94 | uint8_t key[16]; 95 | char b64[64]; 96 | 97 | if (obfs_http->port != 80) 98 | snprintf(host_port, sizeof(host_port), "%s:%d", obfs_http->host, obfs_http->port); 99 | else 100 | snprintf(host_port, sizeof(host_port), "%s", obfs_http->host); 101 | 102 | rand_bytes(key, 16); 103 | base64_encode(b64, 64, key, 16); 104 | 105 | size_t obfs_len = 106 | snprintf(http_header, sizeof(http_header), http_request_template, obfs_http->method, 107 | obfs_http->uri, host_port, major_version, minor_version, b64, buf->len); 108 | size_t buf_len = buf->len; 109 | 110 | brealloc(buf, obfs_len + buf_len, cap); 111 | 112 | memmove(buf->data + obfs_len, buf->data, buf_len); 113 | memcpy(buf->data, http_header, obfs_len); 114 | 115 | buf->len = obfs_len + buf_len; 116 | 117 | return buf->len; 118 | } 119 | 120 | static int 121 | obfs_http_response(buffer_t *buf, size_t cap, obfs_t *obfs) 122 | { 123 | if (obfs == NULL || obfs->obfs_stage != 0) return 0; 124 | obfs->obfs_stage++; 125 | 126 | static int major_version = 0; 127 | static int minor_version = 0; 128 | 129 | major_version = major_version ? major_version : rand() % 11; 130 | minor_version = minor_version ? minor_version : rand() % 12; 131 | 132 | char http_header[512]; 133 | char datetime[64]; 134 | uint8_t key[16]; 135 | char b64[64]; 136 | 137 | time_t now; 138 | struct tm *tm_now; 139 | 140 | time(&now); 141 | tm_now = localtime(&now); 142 | strftime(datetime, 64, "%a, %d %b %Y %H:%M:%S GMT", tm_now); 143 | 144 | rand_bytes(key, 16); 145 | base64_encode(b64, 64, key, 16); 146 | 147 | size_t buf_len = buf->len; 148 | size_t obfs_len = 149 | snprintf(http_header, sizeof(http_header), http_response_template, 150 | major_version, minor_version, datetime, b64); 151 | 152 | brealloc(buf, obfs_len + buf_len, cap); 153 | 154 | memmove(buf->data + obfs_len, buf->data, buf_len); 155 | memcpy(buf->data, http_header, obfs_len); 156 | 157 | buf->len = obfs_len + buf_len; 158 | 159 | return buf->len; 160 | } 161 | 162 | static int 163 | deobfs_http_header(buffer_t *buf, size_t cap, obfs_t *obfs) 164 | { 165 | if (obfs == NULL || obfs->deobfs_stage != 0) return 0; 166 | 167 | char *data = buf->data; 168 | int len = buf->len; 169 | int err = -1; 170 | 171 | // Allow empty content 172 | while (len >= 4) { 173 | if (data[0] == '\r' && data[1] == '\n' 174 | && data[2] == '\r' && data[3] == '\n') { 175 | len -= 4; 176 | data += 4; 177 | err = 0; 178 | break; 179 | } 180 | len--; 181 | data++; 182 | } 183 | 184 | if (!err) { 185 | memmove(buf->data, data, len); 186 | buf->len = len; 187 | obfs->deobfs_stage++; 188 | } 189 | 190 | return err; 191 | } 192 | 193 | static int 194 | check_http_header(buffer_t *buf) 195 | { 196 | char *data = buf->data; 197 | int len = buf->len; 198 | 199 | char *lfpos= strchr(data, '\n'); 200 | if (lfpos == NULL) return OBFS_NEED_MORE; 201 | if (len < 15) return OBFS_ERROR; 202 | if (strncasecmp(lfpos - 9, "HTTP/1.1", 8) != 0) return OBFS_ERROR; 203 | if ( obfs_http->method != NULL && strncasecmp(data, obfs_http->method, strlen(obfs_http->method)) != 0) 204 | return OBFS_ERROR; 205 | 206 | { 207 | char *protocol; 208 | int result = get_header("Upgrade:", data, len, &protocol); 209 | if (result < 0) { 210 | if (result == -1) 211 | return OBFS_NEED_MORE; 212 | else 213 | return OBFS_ERROR; 214 | } 215 | if (strncmp(protocol, "websocket", result) != 0) { 216 | free(protocol); 217 | return OBFS_ERROR; 218 | } else { 219 | free(protocol); 220 | } 221 | } 222 | 223 | if (obfs_http->host != NULL) { 224 | char *hostname; 225 | int i; 226 | 227 | int result = get_header("Host:", data, len, &hostname); 228 | if (result < 0) { 229 | if (result == -1) 230 | return OBFS_NEED_MORE; 231 | else 232 | return OBFS_ERROR; 233 | } 234 | 235 | /* 236 | * if the user specifies the port in the request, it is included here. 237 | * Host: example.com:80 238 | * so we trim off port portion 239 | */ 240 | for (i = result - 1; i >= 0; i--) 241 | if ((hostname)[i] == ':') { 242 | (hostname)[i] = '\0'; 243 | result = i; 244 | break; 245 | } 246 | 247 | result = OBFS_ERROR; 248 | if (strncasecmp(hostname, obfs_http->host, len) == 0) { 249 | result = OBFS_OK; 250 | } 251 | free(hostname); 252 | return result; 253 | } 254 | 255 | return OBFS_OK; 256 | } 257 | 258 | static int 259 | get_header(const char *header, const char *data, int data_len, char **value) 260 | { 261 | int len, header_len; 262 | 263 | header_len = strlen(header); 264 | 265 | /* loop through headers stopping at first blank line */ 266 | while ((len = next_header(&data, &data_len)) != 0) 267 | if (len > header_len && strncasecmp(header, data, header_len) == 0) { 268 | /* Eat leading whitespace */ 269 | while (header_len < len && isblank((unsigned char)data[header_len])) 270 | header_len++; 271 | 272 | *value = malloc(len - header_len + 1); 273 | if (*value == NULL) 274 | return -4; 275 | 276 | strncpy(*value, data + header_len, len - header_len); 277 | (*value)[len - header_len] = '\0'; 278 | 279 | return len - header_len; 280 | } 281 | 282 | /* If there is no data left after reading all the headers then we do not 283 | * have a complete HTTP request, there must be a blank line */ 284 | if (data_len == 0) 285 | return -1; 286 | 287 | return -2; 288 | } 289 | 290 | static int 291 | next_header(const char **data, int *len) 292 | { 293 | int header_len; 294 | 295 | /* perhaps we can optimize this to reuse the value of header_len, rather 296 | * than scanning twice. 297 | * Walk our data stream until the end of the header */ 298 | while (*len > 2 && (*data)[0] != '\r' && (*data)[1] != '\n') { 299 | (*len)--; 300 | (*data)++; 301 | } 302 | 303 | /* advanced past the pair */ 304 | *data += 2; 305 | *len -= 2; 306 | 307 | /* Find the length of the next header */ 308 | header_len = 0; 309 | while (*len > header_len + 1 310 | && (*data)[header_len] != '\r' 311 | && (*data)[header_len + 1] != '\n') 312 | header_len++; 313 | 314 | return header_len; 315 | } 316 | 317 | static void 318 | disable_http(obfs_t *obfs) 319 | { 320 | obfs->obfs_stage = -1; 321 | obfs->deobfs_stage = -1; 322 | } 323 | 324 | static int 325 | is_enable_http(obfs_t *obfs) 326 | { 327 | return obfs->obfs_stage != -1 && obfs->deobfs_stage != -1; 328 | } 329 | -------------------------------------------------------------------------------- /src/netutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * netutils.c - Network utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | 27 | #ifdef HAVE_CONFIG_H 28 | #include "config.h" 29 | #endif 30 | 31 | #ifdef __MINGW32__ 32 | #include "win32.h" 33 | #define sleep(n) Sleep(1000 * (n)) 34 | #else 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #endif 41 | 42 | #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) 43 | #include 44 | #include 45 | #define SET_INTERFACE 46 | #endif 47 | 48 | #include "netutils.h" 49 | #include "utils.h" 50 | 51 | #ifndef SO_REUSEPORT 52 | #define SO_REUSEPORT 15 53 | #endif 54 | 55 | extern int verbose; 56 | 57 | static const char valid_label_bytes[] = 58 | "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; 59 | 60 | #if defined(MODULE_LOCAL) 61 | extern int keep_resolving; 62 | #endif 63 | 64 | int 65 | set_reuseport(int socket) 66 | { 67 | int opt = 1; 68 | return setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); 69 | } 70 | 71 | size_t 72 | get_sockaddr_len(struct sockaddr *addr) 73 | { 74 | if (addr->sa_family == AF_INET) { 75 | return sizeof(struct sockaddr_in); 76 | } else if (addr->sa_family == AF_INET6) { 77 | return sizeof(struct sockaddr_in6); 78 | } 79 | return 0; 80 | } 81 | 82 | #ifdef SET_INTERFACE 83 | int 84 | setinterface(int socket_fd, const char *interface_name) 85 | { 86 | struct ifreq interface; 87 | memset(&interface, 0, sizeof(struct ifreq)); 88 | strncpy(interface.ifr_name, interface_name, IFNAMSIZ - 1); 89 | interface.ifr_name[IFNAMSIZ - 1] = '\0'; 90 | int res = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, 91 | sizeof(struct ifreq)); 92 | return res; 93 | } 94 | #endif 95 | 96 | int 97 | bind_to_address(int socket_fd, const char *host) 98 | { 99 | if (host != NULL) { 100 | struct cork_ip ip; 101 | struct sockaddr_storage storage; 102 | memset(&storage, 0, sizeof(struct sockaddr_storage)); 103 | if (cork_ip_init(&ip, host) != -1) { 104 | if (ip.version == 4) { 105 | struct sockaddr_in *addr = (struct sockaddr_in *)&storage; 106 | inet_pton(AF_INET, host, &addr->sin_addr); 107 | addr->sin_family = AF_INET; 108 | return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); 109 | } else if (ip.version == 6) { 110 | struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage; 111 | inet_pton(AF_INET6, host, &addr->sin6_addr); 112 | addr->sin6_family = AF_INET6; 113 | return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6)); 114 | } 115 | } 116 | } 117 | return -1; 118 | } 119 | 120 | ssize_t 121 | get_sockaddr(char *host, char *port, 122 | struct sockaddr_storage *storage, int block, 123 | int ipv6first) 124 | { 125 | struct cork_ip ip; 126 | if (cork_ip_init(&ip, host) != -1) { 127 | if (ip.version == 4) { 128 | struct sockaddr_in *addr = (struct sockaddr_in *)storage; 129 | addr->sin_family = AF_INET; 130 | inet_pton(AF_INET, host, &(addr->sin_addr)); 131 | if (port != NULL) { 132 | addr->sin_port = htons(atoi(port)); 133 | } 134 | } else if (ip.version == 6) { 135 | struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; 136 | addr->sin6_family = AF_INET6; 137 | inet_pton(AF_INET6, host, &(addr->sin6_addr)); 138 | if (port != NULL) { 139 | addr->sin6_port = htons(atoi(port)); 140 | } 141 | } 142 | return 0; 143 | } else { 144 | struct addrinfo hints; 145 | struct addrinfo *result, *rp; 146 | 147 | memset(&hints, 0, sizeof(struct addrinfo)); 148 | hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ 149 | hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ 150 | 151 | int err, i; 152 | 153 | for (i = 1; i < 8; i++) { 154 | err = getaddrinfo(host, port, &hints, &result); 155 | #if defined(MODULE_LOCAL) 156 | if (!keep_resolving) 157 | break; 158 | #endif 159 | if ((!block || !err)) { 160 | break; 161 | } else { 162 | sleep(pow(2, i)); 163 | LOGE("failed to resolve server name, wait %.0f seconds", pow(2, i)); 164 | } 165 | } 166 | 167 | if (err != 0) { 168 | LOGE("getaddrinfo: %s", gai_strerror(err)); 169 | return -1; 170 | } 171 | 172 | int prefer_af = ipv6first ? AF_INET6 : AF_INET; 173 | for (rp = result; rp != NULL; rp = rp->ai_next) 174 | if (rp->ai_family == prefer_af) { 175 | if (rp->ai_family == AF_INET) 176 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); 177 | else if (rp->ai_family == AF_INET6) 178 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); 179 | break; 180 | } 181 | 182 | if (rp == NULL) { 183 | for (rp = result; rp != NULL; rp = rp->ai_next) { 184 | if (rp->ai_family == AF_INET) 185 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in)); 186 | else if (rp->ai_family == AF_INET6) 187 | memcpy(storage, rp->ai_addr, sizeof(struct sockaddr_in6)); 188 | break; 189 | } 190 | } 191 | 192 | if (rp == NULL) { 193 | LOGE("failed to resolve remote addr"); 194 | return -1; 195 | } 196 | 197 | freeaddrinfo(result); 198 | return 0; 199 | } 200 | 201 | return -1; 202 | } 203 | 204 | int 205 | sockaddr_cmp(struct sockaddr_storage *addr1, 206 | struct sockaddr_storage *addr2, socklen_t len) 207 | { 208 | struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1; 209 | struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2; 210 | struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1; 211 | struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2; 212 | if (p1_in->sin_family < p2_in->sin_family) 213 | return -1; 214 | if (p1_in->sin_family > p2_in->sin_family) 215 | return 1; 216 | if (verbose) { 217 | LOGI("sockaddr_cmp: sin_family equal? %d", p1_in->sin_family == p2_in->sin_family); 218 | } 219 | /* compare ip4 */ 220 | if (p1_in->sin_family == AF_INET) { 221 | /* just order it, ntohs not required */ 222 | if (p1_in->sin_port < p2_in->sin_port) 223 | return -1; 224 | if (p1_in->sin_port > p2_in->sin_port) 225 | return 1; 226 | if (verbose) { 227 | LOGI("sockaddr_cmp: sin_port equal? %d", p1_in->sin_port == p2_in->sin_port); 228 | } 229 | return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); 230 | } else if (p1_in6->sin6_family == AF_INET6) { 231 | /* just order it, ntohs not required */ 232 | if (p1_in6->sin6_port < p2_in6->sin6_port) 233 | return -1; 234 | if (p1_in6->sin6_port > p2_in6->sin6_port) 235 | return 1; 236 | if (verbose) { 237 | LOGI("sockaddr_cmp: sin6_port equal? %d", p1_in6->sin6_port == p2_in6->sin6_port); 238 | } 239 | return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, 240 | INET6_SIZE); 241 | } else { 242 | /* eek unknown type, perform this comparison for sanity. */ 243 | return memcmp(addr1, addr2, len); 244 | } 245 | } 246 | 247 | int 248 | sockaddr_cmp_addr(struct sockaddr_storage *addr1, 249 | struct sockaddr_storage *addr2, socklen_t len) 250 | { 251 | struct sockaddr_in *p1_in = (struct sockaddr_in *)addr1; 252 | struct sockaddr_in *p2_in = (struct sockaddr_in *)addr2; 253 | struct sockaddr_in6 *p1_in6 = (struct sockaddr_in6 *)addr1; 254 | struct sockaddr_in6 *p2_in6 = (struct sockaddr_in6 *)addr2; 255 | if (p1_in->sin_family < p2_in->sin_family) 256 | return -1; 257 | if (p1_in->sin_family > p2_in->sin_family) 258 | return 1; 259 | if (verbose) { 260 | LOGI("sockaddr_cmp_addr: sin_family equal? %d", p1_in->sin_family == p2_in->sin_family); 261 | } 262 | /* compare ip4 */ 263 | if (p1_in->sin_family == AF_INET) { 264 | return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE); 265 | } else if (p1_in6->sin6_family == AF_INET6) { 266 | return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr, 267 | INET6_SIZE); 268 | } else { 269 | /* eek unknown type, perform this comparison for sanity. */ 270 | return memcmp(addr1, addr2, len); 271 | } 272 | } 273 | 274 | int 275 | validate_hostname(const char *hostname, const int hostname_len) 276 | { 277 | if (hostname == NULL) 278 | return 0; 279 | 280 | if (hostname_len < 1 || hostname_len > 255) 281 | return 0; 282 | 283 | if (hostname[0] == '.') 284 | return 0; 285 | 286 | const char *label = hostname; 287 | while (label < hostname + hostname_len) { 288 | size_t label_len = hostname_len - (label - hostname); 289 | char *next_dot = strchr(label, '.'); 290 | if (next_dot != NULL) 291 | label_len = next_dot - label; 292 | 293 | if (label + label_len > hostname + hostname_len) 294 | return 0; 295 | 296 | if (label_len > 63 || label_len < 1) 297 | return 0; 298 | 299 | if (label[0] == '-' || label[label_len - 1] == '-') 300 | return 0; 301 | 302 | if (strspn(label, valid_label_bytes) < label_len) 303 | return 0; 304 | 305 | label += label_len + 1; 306 | } 307 | 308 | return 1; 309 | } 310 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.c - Misc utilities 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #ifndef __MINGW32__ 33 | #include 34 | #include 35 | #endif 36 | 37 | #include 38 | #include 39 | 40 | #include "utils.h" 41 | 42 | #ifdef HAVE_SETRLIMIT 43 | #include 44 | #include 45 | #endif 46 | 47 | #define INT_DIGITS 19 /* enough for 64 bit integer */ 48 | 49 | #ifdef LIB_ONLY 50 | FILE *logfile; 51 | #endif 52 | 53 | #ifdef HAS_SYSLOG 54 | int use_syslog = 0; 55 | #endif 56 | 57 | #ifndef __MINGW32__ 58 | void 59 | ERROR(const char *s) 60 | { 61 | char *msg = strerror(errno); 62 | LOGE("%s: %s", s, msg); 63 | } 64 | 65 | #endif 66 | 67 | int use_tty = 1; 68 | 69 | char * 70 | ss_itoa(int i) 71 | { 72 | /* Room for INT_DIGITS digits, - and '\0' */ 73 | static char buf[INT_DIGITS + 2]; 74 | char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ 75 | if (i >= 0) { 76 | do { 77 | *--p = '0' + (i % 10); 78 | i /= 10; 79 | } while (i != 0); 80 | return p; 81 | } else { /* i < 0 */ 82 | do { 83 | *--p = '0' - (i % 10); 84 | i /= 10; 85 | } while (i != 0); 86 | *--p = '-'; 87 | } 88 | return p; 89 | } 90 | 91 | int 92 | ss_isnumeric(const char *s) { 93 | if (!s || !*s) 94 | return 0; 95 | while (isdigit(*s)) 96 | ++s; 97 | return *s == '\0'; 98 | } 99 | 100 | /* 101 | * setuid() and setgid() for a specified user. 102 | */ 103 | int 104 | run_as(const char *user) 105 | { 106 | #ifndef __MINGW32__ 107 | if (user[0]) { 108 | /* Convert user to a long integer if it is a non-negative number. 109 | * -1 means it is a user name. */ 110 | long uid = -1; 111 | if (ss_isnumeric(user)) { 112 | errno = 0; 113 | char *endptr; 114 | uid = strtol(user, &endptr, 10); 115 | if (errno || endptr == user) 116 | uid = -1; 117 | } 118 | 119 | #ifdef HAVE_GETPWNAM_R 120 | struct passwd pwdbuf, *pwd; 121 | memset(&pwdbuf, 0, sizeof(struct passwd)); 122 | size_t buflen; 123 | int err; 124 | 125 | for (buflen = 128;; buflen *= 2) { 126 | char buf[buflen]; /* variable length array */ 127 | 128 | /* Note that we use getpwnam_r() instead of getpwnam(), 129 | * which returns its result in a statically allocated buffer and 130 | * cannot be considered thread safe. */ 131 | err = uid >= 0 ? getpwuid_r((uid_t)uid, &pwdbuf, buf, buflen, &pwd) 132 | : getpwnam_r(user, &pwdbuf, buf, buflen, &pwd); 133 | 134 | if (err == 0 && pwd) { 135 | /* setgid first, because we may not be allowed to do it anymore after setuid */ 136 | if (setgid(pwd->pw_gid) != 0) { 137 | LOGE( 138 | "Could not change group id to that of run_as user '%s': %s", 139 | pwd->pw_name, strerror(errno)); 140 | return 0; 141 | } 142 | 143 | if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 144 | LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name); 145 | return 0; 146 | } 147 | 148 | if (setuid(pwd->pw_uid) != 0) { 149 | LOGE( 150 | "Could not change user id to that of run_as user '%s': %s", 151 | pwd->pw_name, strerror(errno)); 152 | return 0; 153 | } 154 | break; 155 | } else if (err != ERANGE) { 156 | if (err) { 157 | LOGE("run_as user '%s' could not be found: %s", user, 158 | strerror(err)); 159 | } else { 160 | LOGE("run_as user '%s' could not be found.", user); 161 | } 162 | return 0; 163 | } else if (buflen >= 16 * 1024) { 164 | /* If getpwnam_r() seems defective, call it quits rather than 165 | * keep on allocating ever larger buffers until we crash. */ 166 | LOGE( 167 | "getpwnam_r() requires more than %u bytes of buffer space.", 168 | (unsigned)buflen); 169 | return 0; 170 | } 171 | /* Else try again with larger buffer. */ 172 | } 173 | #else 174 | /* No getpwnam_r() :-( We'll use getpwnam() and hope for the best. */ 175 | struct passwd *pwd; 176 | 177 | if (!(pwd = uid >=0 ? getpwuid((uid_t)uid) : getpwnam(user))) { 178 | LOGE("run_as user %s could not be found.", user); 179 | return 0; 180 | } 181 | /* setgid first, because we may not allowed to do it anymore after setuid */ 182 | if (setgid(pwd->pw_gid) != 0) { 183 | LOGE("Could not change group id to that of run_as user '%s': %s", 184 | pwd->pw_name, strerror(errno)); 185 | return 0; 186 | } 187 | if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 188 | LOGE("Could not change supplementary groups for user '%s'.", pwd->pw_name); 189 | return 0; 190 | } 191 | if (setuid(pwd->pw_uid) != 0) { 192 | LOGE("Could not change user id to that of run_as user '%s': %s", 193 | pwd->pw_name, strerror(errno)); 194 | return 0; 195 | } 196 | #endif 197 | } 198 | 199 | #endif // __MINGW32__ 200 | return 1; 201 | } 202 | 203 | char * 204 | ss_strndup(const char *s, size_t n) 205 | { 206 | size_t len = strlen(s); 207 | char *ret; 208 | 209 | if (len <= n) { 210 | return strdup(s); 211 | } 212 | 213 | ret = ss_malloc(n + 1); 214 | strncpy(ret, s, n); 215 | ret[n] = '\0'; 216 | return ret; 217 | } 218 | 219 | void 220 | FATAL(const char *msg) 221 | { 222 | LOGE("%s", msg); 223 | exit(-1); 224 | } 225 | 226 | void * 227 | ss_malloc(size_t size) 228 | { 229 | void *tmp = malloc(size); 230 | if (tmp == NULL) 231 | exit(EXIT_FAILURE); 232 | return tmp; 233 | } 234 | 235 | void * 236 | ss_realloc(void *ptr, size_t new_size) 237 | { 238 | void *new = realloc(ptr, new_size); 239 | if (new == NULL) { 240 | free(ptr); 241 | ptr = NULL; 242 | exit(EXIT_FAILURE); 243 | } 244 | return new; 245 | } 246 | 247 | void 248 | usage() 249 | { 250 | printf("\n"); 251 | printf("simple-obfs %s\n\n", VERSION); 252 | printf( 253 | " maintained by Max Lv \n\n"); 254 | printf(" usage:\n\n"); 255 | #ifdef MODULE_LOCAL 256 | printf(" obfs-local\n"); 257 | #elif MODULE_REMOTE 258 | printf(" obfs-server\n"); 259 | #endif 260 | printf("\n"); 261 | printf( 262 | " -s Host name or IP address of your remote server.\n"); 263 | printf( 264 | " -p Port number of your remote server.\n"); 265 | printf( 266 | " -l Port number of your local server.\n"); 267 | #ifdef MODULE_REMOTE 268 | printf( 269 | " -r : Forward traffic to this remote server address.\n"); 270 | #endif 271 | printf( 272 | " --obfs Enable obfuscating: HTTP or TLS (Experimental).\n"); 273 | printf( 274 | " --http-method HTTP request method for obfuscating (Experimental).\n"); 275 | #ifndef MODULE_REMOTE 276 | printf( 277 | " --obfs-host Hostname for obfuscating (Experimental).\n"); 278 | printf( 279 | " --obfs-uri HTTP path uri for obfuscating (Experimental).\n"); 280 | #endif 281 | printf("\n"); 282 | printf( 283 | " [-a ] Run as another user.\n"); 284 | printf( 285 | " [-f ] The file path to store pid.\n"); 286 | printf( 287 | " [-t ] Socket timeout in seconds.\n"); 288 | printf( 289 | " [-c ] The path to config file.\n"); 290 | #ifdef HAVE_SETRLIMIT 291 | printf( 292 | " [-n ] Max number of open files.\n"); 293 | #endif 294 | printf( 295 | " [-b ] Local address to bind.\n"); 296 | printf("\n"); 297 | #ifdef MODULE_REMOTE 298 | printf( 299 | " [-6] Resovle hostname to IPv6 address first.\n"); 300 | #endif 301 | printf("\n"); 302 | #ifdef MODULE_REMOTE 303 | printf( 304 | " [-d ] Name servers for internal DNS resolver.\n"); 305 | #endif 306 | #if defined(MODULE_REMOTE) || defined(MODULE_LOCAL) 307 | printf( 308 | " [--fast-open] Enable TCP fast open.\n"); 309 | printf( 310 | " with Linux kernel > 3.7.0.\n"); 311 | #endif 312 | #ifdef __linux__ 313 | printf( 314 | " [--mptcp] Enable Multipath TCP on MPTCP Kernel.\n"); 315 | #endif 316 | printf("\n"); 317 | printf( 318 | " [-v] Verbose mode.\n"); 319 | printf( 320 | " [-h, --help] Print this message.\n"); 321 | printf("\n"); 322 | fflush(stdout); 323 | } 324 | 325 | void 326 | daemonize(const char *path) 327 | { 328 | #ifndef __MINGW32__ 329 | /* Our process ID and Session ID */ 330 | pid_t pid, sid; 331 | 332 | /* Fork off the parent process */ 333 | pid = fork(); 334 | if (pid < 0) { 335 | exit(EXIT_FAILURE); 336 | } 337 | 338 | /* If we got a good PID, then 339 | * we can exit the parent process. */ 340 | if (pid > 0) { 341 | FILE *file = fopen(path, "w"); 342 | if (file == NULL) { 343 | FATAL("Invalid pid file\n"); 344 | } 345 | 346 | fprintf(file, "%d", (int)pid); 347 | fclose(file); 348 | exit(EXIT_SUCCESS); 349 | } 350 | 351 | /* Change the file mode mask */ 352 | umask(0); 353 | 354 | /* Open any logs here */ 355 | 356 | /* Create a new SID for the child process */ 357 | sid = setsid(); 358 | if (sid < 0) { 359 | /* Log the failure */ 360 | exit(EXIT_FAILURE); 361 | } 362 | 363 | /* Change the current working directory */ 364 | if ((chdir("/")) < 0) { 365 | /* Log the failure */ 366 | exit(EXIT_FAILURE); 367 | } 368 | 369 | /* Close out the standard file descriptors */ 370 | close(STDIN_FILENO); 371 | close(STDOUT_FILENO); 372 | close(STDERR_FILENO); 373 | #endif 374 | } 375 | 376 | #ifdef HAVE_SETRLIMIT 377 | int 378 | set_nofile(int nofile) 379 | { 380 | struct rlimit limit = { nofile, nofile }; /* set both soft and hard limit */ 381 | 382 | if (nofile <= 0) { 383 | FATAL("nofile must be greater than 0\n"); 384 | } 385 | 386 | if (setrlimit(RLIMIT_NOFILE, &limit) < 0) { 387 | if (errno == EPERM) { 388 | LOGE( 389 | "insufficient permission to change NOFILE, not starting as root?"); 390 | return -1; 391 | } else if (errno == EINVAL) { 392 | LOGE("invalid nofile, decrease nofile and try again"); 393 | return -1; 394 | } else { 395 | LOGE("setrlimit failed: %s", strerror(errno)); 396 | return -1; 397 | } 398 | } 399 | 400 | return 0; 401 | } 402 | #endif 403 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell commands `./configure; make; make install' should 16 | configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 230 | parse its `' header file. The option `-nodtk' can be used as 231 | a workaround. If GNU CC is not installed, it is therefore recommended 232 | to try 233 | 234 | ./configure CC="cc" 235 | 236 | and if that doesn't work, try 237 | 238 | ./configure CC="cc -nodtk" 239 | 240 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 241 | directory contains several dysfunctional programs; working variants of 242 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 243 | in your `PATH', put it _after_ `/usr/bin'. 244 | 245 | On Haiku, software installed for all users goes in `/boot/common', 246 | not `/usr/local'. It is recommended to use the following options: 247 | 248 | ./configure --prefix=/boot/common 249 | 250 | Specifying the System Type 251 | ========================== 252 | 253 | There may be some features `configure' cannot figure out 254 | automatically, but needs to determine by the type of machine the package 255 | will run on. Usually, assuming the package is built to be run on the 256 | _same_ architectures, `configure' can figure that out, but if it prints 257 | a message saying it cannot guess the machine type, give it the 258 | `--build=TYPE' option. TYPE can either be a short name for the system 259 | type, such as `sun4', or a canonical name which has the form: 260 | 261 | CPU-COMPANY-SYSTEM 262 | 263 | where SYSTEM can have one of these forms: 264 | 265 | OS 266 | KERNEL-OS 267 | 268 | See the file `config.sub' for the possible values of each field. If 269 | `config.sub' isn't included in this package, then this package doesn't 270 | need to know the machine type. 271 | 272 | If you are _building_ compiler tools for cross-compiling, you should 273 | use the option `--target=TYPE' to select the type of system they will 274 | produce code for. 275 | 276 | If you want to _use_ a cross compiler, that generates code for a 277 | platform different from the build platform, you should specify the 278 | "host" platform (i.e., that on which the generated programs will 279 | eventually be run) with `--host=TYPE'. 280 | 281 | Sharing Defaults 282 | ================ 283 | 284 | If you want to set default values for `configure' scripts to share, 285 | you can create a site shell script called `config.site' that gives 286 | default values for variables like `CC', `cache_file', and `prefix'. 287 | `configure' looks for `PREFIX/share/config.site' if it exists, then 288 | `PREFIX/etc/config.site' if it exists. Or, you can set the 289 | `CONFIG_SITE' environment variable to the location of the site script. 290 | A warning: not all `configure' scripts look for a site script. 291 | 292 | Defining Variables 293 | ================== 294 | 295 | Variables not defined in a site shell script can be set in the 296 | environment passed to `configure'. However, some packages may run 297 | configure again during the build, and the customized values of these 298 | variables may be lost. In order to avoid this problem, you should set 299 | them in the `configure' command line, using `VAR=value'. For example: 300 | 301 | ./configure CC=/usr/local2/bin/gcc 302 | 303 | causes the specified `gcc' to be used as the C compiler (unless it is 304 | overridden in the site shell script). 305 | 306 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 307 | an Autoconf bug. Until the bug is fixed you can use this workaround: 308 | 309 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 310 | 311 | `configure' Invocation 312 | ====================== 313 | 314 | `configure' recognizes the following options to control how it 315 | operates. 316 | 317 | `--help' 318 | `-h' 319 | Print a summary of all of the options to `configure', and exit. 320 | 321 | `--help=short' 322 | `--help=recursive' 323 | Print a summary of the options unique to this package's 324 | `configure', and exit. The `short' variant lists options used 325 | only in the top level, while the `recursive' variant lists options 326 | also present in any nested packages. 327 | 328 | `--version' 329 | `-V' 330 | Print the version of Autoconf used to generate the `configure' 331 | script, and exit. 332 | 333 | `--cache-file=FILE' 334 | Enable the cache: use and save the results of the tests in FILE, 335 | traditionally `config.cache'. FILE defaults to `/dev/null' to 336 | disable caching. 337 | 338 | `--config-cache' 339 | `-C' 340 | Alias for `--cache-file=config.cache'. 341 | 342 | `--quiet' 343 | `--silent' 344 | `-q' 345 | Do not print messages saying which checks are being made. To 346 | suppress all normal output, redirect it to `/dev/null' (any error 347 | messages will still be shown). 348 | 349 | `--srcdir=DIR' 350 | Look for the package's source code in directory DIR. Usually 351 | `configure' can determine that directory automatically. 352 | 353 | `--prefix=DIR' 354 | Use DIR as the installation prefix. *note Installation Names:: 355 | for more details, including other options available for fine-tuning 356 | the installation locations. 357 | 358 | `--no-create' 359 | `-n' 360 | Run the configure checks, but stop before creating any output 361 | files. 362 | 363 | `configure' also accepts some other, not widely useful, options. Run 364 | `configure --help' for more details. 365 | 366 | -------------------------------------------------------------------------------- /src/obfs_tls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * obfs_tls.c - Implementation of tls obfuscating 3 | * 4 | * Copyright (C) 2013 - 2016, Max Lv 5 | * 6 | * This file is part of the simple-obfs. 7 | * 8 | * simple-obfs is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * simple-obfs is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with simple-obfs; see the file COPYING. If not, see 20 | * . 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | 29 | #include 30 | 31 | #define CT_HTONS(n) CORK_UINT16_HOST_TO_BIG(n) 32 | #define CT_NTOHS(n) CORK_UINT16_BIG_TO_HOST(n) 33 | #define CT_HTONL(n) CORK_UINT32_HOST_TO_BIG(n) 34 | #define CT_NTOHL(n) CORK_UINT32_BIG_TO_HOST(n) 35 | 36 | #include "base64.h" 37 | #include "utils.h" 38 | #include "obfs_tls.h" 39 | 40 | static const struct tls_client_hello 41 | tls_client_hello_template = { 42 | .content_type = 0x16, 43 | .version = CT_HTONS(0x0301), 44 | .len = 0, 45 | 46 | .handshake_type = 1, 47 | .handshake_len_1 = 0, 48 | .handshake_len_2 = 0, 49 | .handshake_version = CT_HTONS(0x0303), 50 | 51 | .random_unix_time = 0, 52 | .random_bytes = { 0 }, 53 | 54 | .session_id_len = 32, 55 | .session_id = { 0 }, 56 | 57 | .cipher_suites_len = CT_HTONS(56), 58 | .cipher_suites = { 59 | 0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f, 60 | 0x00, 0x9e, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a, 61 | 0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x3d, 62 | 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0xff 63 | }, 64 | 65 | .comp_methods_len = 1, 66 | .comp_methods = { 0 }, 67 | 68 | .ext_len = 0, 69 | }; 70 | 71 | static const struct tls_ext_server_name 72 | tls_ext_server_name_template = { 73 | .ext_type = 0, 74 | .ext_len = 0, 75 | .server_name_list_len = 0, 76 | .server_name_type = 0, 77 | .server_name_len = 0, 78 | // char server_name[server_name_len]; 79 | }; 80 | 81 | static const struct tls_ext_session_ticket 82 | tls_ext_session_ticket_template = { 83 | .session_ticket_type = CT_HTONS(0x0023), 84 | .session_ticket_ext_len = 0, 85 | // char session_ticket[session_ticket_ext_len]; 86 | }; 87 | 88 | static const struct tls_ext_others 89 | tls_ext_others_template = { 90 | .ec_point_formats_ext_type = CT_HTONS(0x000B), 91 | .ec_point_formats_ext_len = CT_HTONS(4), 92 | .ec_point_formats_len = 3, 93 | .ec_point_formats = { 0x01, 0x00, 0x02 }, 94 | 95 | .elliptic_curves_type = CT_HTONS(0x000a), 96 | .elliptic_curves_ext_len = CT_HTONS(10), 97 | .elliptic_curves_len = CT_HTONS(8), 98 | .elliptic_curves = { 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19, 0x00, 0x18 }, 99 | 100 | .sig_algos_type = CT_HTONS(0x000d), 101 | .sig_algos_ext_len = CT_HTONS(32), 102 | .sig_algos_len = CT_HTONS(30), 103 | .sig_algos = { 104 | 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 105 | 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03 106 | }, 107 | 108 | .encrypt_then_mac_type = CT_HTONS(0x0016), 109 | .encrypt_then_mac_ext_len = 0, 110 | 111 | .extended_master_secret_type = CT_HTONS(0x0017), 112 | .extended_master_secret_ext_len = 0, 113 | }; 114 | 115 | static const struct tls_server_hello 116 | tls_server_hello_template = { 117 | .content_type = 0x16, 118 | .version = CT_HTONS(0x0301), 119 | .len = CT_HTONS(91), 120 | 121 | .handshake_type = 2, 122 | .handshake_len_1 = 0, 123 | .handshake_len_2 = CT_HTONS(87), 124 | .handshake_version = CT_HTONS(0x0303), 125 | 126 | .random_unix_time = 0, 127 | .random_bytes = { 0 }, 128 | 129 | .session_id_len = 32, 130 | .session_id = { 0 }, 131 | 132 | .cipher_suite = CT_HTONS(0xCCA8), 133 | .comp_method = 0, 134 | .ext_len = 0, 135 | 136 | .ext_renego_info_type = CT_HTONS(0xFF01), 137 | .ext_renego_info_ext_len = CT_HTONS(1), 138 | .ext_renego_info_len = 0, 139 | 140 | .extended_master_secret_type = CT_HTONS(0x0017), 141 | .extended_master_secret_ext_len = 0, 142 | 143 | .ec_point_formats_ext_type = CT_HTONS(0x000B), 144 | .ec_point_formats_ext_len = CT_HTONS(2), 145 | .ec_point_formats_len = 1, 146 | .ec_point_formats = { 0 }, 147 | }; 148 | 149 | static const struct tls_change_cipher_spec 150 | tls_change_cipher_spec_template = { 151 | .content_type = 0x14, 152 | .version = CT_HTONS(0x0303), 153 | .len = CT_HTONS(1), 154 | .msg = 0x01, 155 | }; 156 | 157 | static const struct tls_encrypted_handshake 158 | tls_encrypted_handshake_template = { 159 | .content_type = 0x16, 160 | .version = CT_HTONS(0x0303), 161 | .len = 0, 162 | // char msg[len]; 163 | }; 164 | 165 | const char tls_data_header[3] = {0x17, 0x03, 0x03}; 166 | 167 | static int obfs_tls_request(buffer_t *, size_t, obfs_t *); 168 | static int obfs_tls_response(buffer_t *, size_t, obfs_t *); 169 | static int deobfs_tls_request(buffer_t *, size_t, obfs_t *); 170 | static int deobfs_tls_response(buffer_t *, size_t, obfs_t *); 171 | static int obfs_app_data(buffer_t *, size_t, obfs_t *); 172 | static int deobfs_app_data(buffer_t *, size_t, obfs_t *); 173 | static int check_tls_request(buffer_t *buf); 174 | static void disable_tls(obfs_t *obfs); 175 | static int is_enable_tls(obfs_t *obfs); 176 | 177 | static obfs_para_t obfs_tls_st = { 178 | .name = "tls", 179 | .port = 443, 180 | .send_empty_response_upon_connection = false, 181 | 182 | .obfs_request = &obfs_tls_request, 183 | .obfs_response = &obfs_tls_response, 184 | .deobfs_request = &deobfs_tls_request, 185 | .deobfs_response = &deobfs_tls_response, 186 | .check_obfs = &check_tls_request, 187 | .disable = &disable_tls, 188 | .is_enable = &is_enable_tls 189 | }; 190 | 191 | obfs_para_t *obfs_tls = &obfs_tls_st; 192 | 193 | static int 194 | obfs_app_data(buffer_t *buf, size_t cap, obfs_t *obfs) 195 | { 196 | size_t buf_len = buf->len; 197 | 198 | brealloc(buf, buf_len + 5, cap); 199 | memmove(buf->data + 5, buf->data, buf_len); 200 | memcpy(buf->data, tls_data_header, 3); 201 | 202 | *(uint16_t*)(buf->data + 3) = CT_HTONS(buf_len); 203 | buf->len = buf_len + 5; 204 | 205 | return 0; 206 | } 207 | 208 | static int 209 | deobfs_app_data(buffer_t *buf, size_t idx, obfs_t *obfs) 210 | { 211 | int bidx = idx, bofst = idx; 212 | 213 | frame_t *frame = (frame_t *)obfs->extra; 214 | 215 | while (bidx < buf->len) { 216 | if (frame->len == 0) { 217 | if (frame->idx >= 0 && frame->idx < 3 218 | && buf->data[bidx] != tls_data_header[frame->idx]) { 219 | return OBFS_ERROR; 220 | } else if (frame->idx >= 3 && frame->idx < 5) { 221 | memcpy(frame->buf + frame->idx - 3, buf->data + bidx, 1); 222 | } else if (frame->idx < 0) { 223 | bofst++; 224 | } 225 | frame->idx++; 226 | bidx++; 227 | if (frame->idx == 5) { 228 | frame->len = CT_NTOHS(*(uint16_t *)(frame->buf)); 229 | frame->idx = 0; 230 | } 231 | continue; 232 | } 233 | 234 | if (frame->len > 16384) 235 | return OBFS_ERROR; 236 | 237 | int left_len = buf->len - bidx; 238 | 239 | if (left_len > frame->len) { 240 | memmove(buf->data + bofst, buf->data + bidx, frame->len); 241 | bidx += frame->len; 242 | bofst += frame->len; 243 | frame->len = 0; 244 | } else { 245 | memmove(buf->data + bofst, buf->data + bidx, left_len); 246 | bidx = buf->len; 247 | bofst += left_len; 248 | frame->len -= left_len; 249 | } 250 | } 251 | 252 | buf->len = bofst; 253 | 254 | return OBFS_OK; 255 | } 256 | 257 | 258 | static int 259 | obfs_tls_request(buffer_t *buf, size_t cap, obfs_t *obfs) 260 | { 261 | if (obfs == NULL || obfs->obfs_stage < 0) return 0; 262 | 263 | static buffer_t tmp = { 0, 0, 0, NULL }; 264 | 265 | if (obfs->obfs_stage == 0) { 266 | 267 | size_t buf_len = buf->len; 268 | size_t hello_len = sizeof(struct tls_client_hello); 269 | size_t server_name_len = sizeof(struct tls_ext_server_name); 270 | size_t host_len = strlen(obfs_tls->host); 271 | size_t ticket_len = sizeof(struct tls_ext_session_ticket); 272 | size_t other_ext_len = sizeof(struct tls_ext_others); 273 | size_t tls_len = buf_len + hello_len + server_name_len 274 | + host_len + ticket_len + other_ext_len; 275 | 276 | brealloc(&tmp, buf_len, cap); 277 | brealloc(buf, tls_len, cap); 278 | 279 | memcpy(tmp.data, buf->data, buf_len); 280 | 281 | /* Client Hello Header */ 282 | struct tls_client_hello *hello = (struct tls_client_hello *) buf->data; 283 | memcpy(hello, &tls_client_hello_template, hello_len); 284 | hello->len = CT_HTONS(tls_len - 5); 285 | hello->handshake_len_2 = CT_HTONS(tls_len - 9); 286 | hello->random_unix_time = CT_HTONL((uint32_t)time(NULL)); 287 | rand_bytes(hello->random_bytes, 28); 288 | rand_bytes(hello->session_id, 32); 289 | hello->ext_len = CT_HTONS(server_name_len + host_len + ticket_len + buf_len + other_ext_len); 290 | 291 | /* Session Ticket */ 292 | struct tls_ext_session_ticket *ticket = 293 | (struct tls_ext_session_ticket *)((char *)hello + hello_len); 294 | memcpy(ticket, &tls_ext_session_ticket_template, sizeof(struct tls_ext_session_ticket)); 295 | ticket->session_ticket_ext_len = CT_HTONS(buf_len); 296 | memcpy((char *)ticket + ticket_len, tmp.data, buf_len); 297 | 298 | /* SNI */ 299 | struct tls_ext_server_name *server_name = 300 | (struct tls_ext_server_name *)((char *)ticket + ticket_len + buf_len); 301 | memcpy(server_name, &tls_ext_server_name_template, server_name_len); 302 | server_name->ext_len = CT_HTONS(host_len + 3 + 2); 303 | server_name->server_name_list_len = CT_HTONS(host_len + 3); 304 | server_name->server_name_len = CT_HTONS(host_len); 305 | memcpy((char *)server_name + server_name_len, obfs_tls->host, host_len); 306 | 307 | /* Other Extensions */ 308 | memcpy((char *)server_name + server_name_len + host_len, &tls_ext_others_template, 309 | other_ext_len); 310 | 311 | buf->len = tls_len; 312 | 313 | obfs->obfs_stage++; 314 | 315 | } else if (obfs->obfs_stage == 1) { 316 | 317 | obfs_app_data(buf, cap, obfs); 318 | 319 | } 320 | 321 | return buf->len; 322 | } 323 | 324 | static int 325 | obfs_tls_response(buffer_t *buf, size_t cap, obfs_t *obfs) 326 | { 327 | if (obfs == NULL || obfs->obfs_stage < 0) return 0; 328 | 329 | static buffer_t tmp = { 0, 0, 0, NULL }; 330 | 331 | if (obfs->obfs_stage == 0) { 332 | 333 | size_t buf_len = buf->len; 334 | size_t hello_len = sizeof(struct tls_server_hello); 335 | size_t change_cipher_spec_len = sizeof(struct tls_change_cipher_spec); 336 | size_t encrypted_handshake_len = sizeof(struct tls_encrypted_handshake); 337 | size_t tls_len = hello_len + change_cipher_spec_len + encrypted_handshake_len + buf_len; 338 | 339 | brealloc(&tmp, buf_len, cap); 340 | brealloc(buf, tls_len, cap); 341 | 342 | memcpy(tmp.data, buf->data, buf_len); 343 | 344 | /* Server Hello */ 345 | memcpy(buf->data, &tls_server_hello_template, hello_len); 346 | struct tls_server_hello *hello = (struct tls_server_hello *)buf->data; 347 | hello->random_unix_time = CT_HTONL((uint32_t)time(NULL)); 348 | rand_bytes(hello->random_bytes, 28); 349 | if (obfs->buf != NULL) { 350 | memcpy(hello->session_id, obfs->buf->data, 32); 351 | } else { 352 | rand_bytes(hello->session_id, 32); 353 | } 354 | 355 | /* Change Cipher Spec */ 356 | memcpy(buf->data + hello_len, &tls_change_cipher_spec_template, change_cipher_spec_len); 357 | 358 | /* Encrypted Handshake */ 359 | memcpy(buf->data + hello_len + change_cipher_spec_len, &tls_encrypted_handshake_template, 360 | encrypted_handshake_len); 361 | memcpy(buf->data + hello_len + change_cipher_spec_len + encrypted_handshake_len, 362 | tmp.data, buf_len); 363 | 364 | struct tls_encrypted_handshake *encrypted_handshake = 365 | (struct tls_encrypted_handshake *)(buf->data + hello_len + change_cipher_spec_len); 366 | encrypted_handshake->len = CT_HTONS(buf_len); 367 | 368 | buf->len = tls_len; 369 | 370 | obfs->obfs_stage++; 371 | 372 | } else if (obfs->obfs_stage == 1) { 373 | 374 | obfs_app_data(buf, cap, obfs); 375 | 376 | } 377 | 378 | return buf->len; 379 | } 380 | 381 | static int 382 | deobfs_tls_request(buffer_t *buf, size_t cap, obfs_t *obfs) 383 | { 384 | if (obfs == NULL || obfs->deobfs_stage < 0) return 0; 385 | 386 | if (obfs->extra == NULL) { 387 | obfs->extra = ss_malloc(sizeof(frame_t)); 388 | memset(obfs->extra, 0, sizeof(frame_t)); 389 | } 390 | 391 | if (obfs->buf == NULL) { 392 | obfs->buf = (buffer_t *)ss_malloc(sizeof(buffer_t)); 393 | balloc(obfs->buf, 32); 394 | obfs->buf->len = 32; 395 | } 396 | 397 | if (obfs->deobfs_stage == 0) { 398 | 399 | int len = buf->len; 400 | 401 | len -= sizeof(struct tls_client_hello); 402 | if (len <= 0) return OBFS_NEED_MORE; 403 | 404 | struct tls_client_hello *hello = (struct tls_client_hello *) buf->data; 405 | if (hello->content_type != tls_client_hello_template.content_type) 406 | return OBFS_ERROR; 407 | 408 | size_t hello_len = CT_NTOHS(hello->len) + 5; 409 | 410 | memcpy(obfs->buf->data, hello->session_id, 32); 411 | 412 | len -= sizeof(struct tls_ext_session_ticket); 413 | if (len <= 0) return OBFS_NEED_MORE; 414 | 415 | struct tls_ext_session_ticket *ticket = 416 | (struct tls_ext_session_ticket *)(buf->data + sizeof(struct tls_client_hello)); 417 | if (ticket->session_ticket_type != tls_ext_session_ticket_template.session_ticket_type) 418 | return OBFS_ERROR; 419 | 420 | size_t ticket_len = CT_NTOHS(ticket->session_ticket_ext_len); 421 | if (len < ticket_len) 422 | return OBFS_NEED_MORE; 423 | 424 | memmove(buf->data, (char *)ticket + sizeof(struct tls_ext_session_ticket), ticket_len); 425 | 426 | if (buf->len > hello_len) { 427 | memmove(buf->data + ticket_len, buf->data + hello_len, buf->len - hello_len); 428 | } 429 | 430 | buf->len = ticket_len + buf->len - hello_len; 431 | 432 | obfs->deobfs_stage++; 433 | 434 | if (buf->len > ticket_len) { 435 | return deobfs_app_data(buf, ticket_len, obfs); 436 | } else { 437 | ((frame_t*)obfs->extra)->idx = buf->len - ticket_len; 438 | } 439 | 440 | } else if (obfs->deobfs_stage == 1) { 441 | 442 | return deobfs_app_data(buf, 0, obfs); 443 | 444 | } 445 | 446 | return 0; 447 | } 448 | 449 | static int 450 | deobfs_tls_response(buffer_t *buf, size_t cap, obfs_t *obfs) 451 | { 452 | if (obfs == NULL || obfs->deobfs_stage < 0) return 0; 453 | 454 | if (obfs->extra == NULL) { 455 | obfs->extra = ss_malloc(sizeof(frame_t)); 456 | memset(obfs->extra, 0, sizeof(frame_t)); 457 | } 458 | 459 | if (obfs->deobfs_stage == 0) { 460 | 461 | size_t hello_len = sizeof(struct tls_server_hello); 462 | 463 | char *data = buf->data; 464 | int len = buf->len; 465 | 466 | len -= hello_len; 467 | if (len <= 0) return OBFS_NEED_MORE; 468 | 469 | struct tls_server_hello *hello = (struct tls_server_hello*) data; 470 | if (hello->content_type != tls_server_hello_template.content_type) 471 | return OBFS_ERROR; 472 | 473 | size_t change_cipher_spec_len = sizeof(struct tls_change_cipher_spec); 474 | size_t encrypted_handshake_len = sizeof(struct tls_encrypted_handshake); 475 | 476 | len -= change_cipher_spec_len + encrypted_handshake_len; 477 | if (len <= 0) return OBFS_NEED_MORE; 478 | 479 | size_t tls_len = hello_len + change_cipher_spec_len + encrypted_handshake_len; 480 | struct tls_encrypted_handshake *encrypted_handshake = 481 | (struct tls_encrypted_handshake *)(buf->data + hello_len + change_cipher_spec_len); 482 | size_t msg_len = CT_NTOHS(encrypted_handshake->len); 483 | 484 | memmove(buf->data, buf->data + tls_len, buf->len - tls_len); 485 | 486 | buf->len = buf->len - tls_len; 487 | 488 | obfs->deobfs_stage++; 489 | 490 | if (buf->len > msg_len) { 491 | return deobfs_app_data(buf, msg_len, obfs); 492 | } else { 493 | ((frame_t*)obfs->extra)->idx = buf->len - msg_len; 494 | } 495 | 496 | } else if (obfs->deobfs_stage == 1) { 497 | 498 | return deobfs_app_data(buf, 0, obfs); 499 | 500 | } 501 | 502 | return 0; 503 | } 504 | 505 | static int 506 | check_tls_request(buffer_t *buf) 507 | { 508 | char *data = buf->data; 509 | int len = buf->len; 510 | 511 | if (len < 11) 512 | return OBFS_NEED_MORE; 513 | 514 | if (data[0] == 0x16 515 | && data[1] == 0x03 516 | && data[2] == 0x01 517 | && data[5] == 0x01 518 | && data[9] == 0x03 519 | && data[10] == 0x03) 520 | return OBFS_OK; 521 | else 522 | return OBFS_ERROR; 523 | } 524 | 525 | static void 526 | disable_tls(obfs_t *obfs) 527 | { 528 | obfs->obfs_stage = -1; 529 | obfs->deobfs_stage = -1; 530 | } 531 | 532 | static int 533 | is_enable_tls(obfs_t *obfs) 534 | { 535 | return obfs->obfs_stage != -1 && obfs->deobfs_stage != -1; 536 | } 537 | --------------------------------------------------------------------------------