Add SSR lib

This commit is contained in:
WindyMadman 2023-08-08 02:10:36 +08:00
parent d407ddb1a1
commit ef2f98a523
65 changed files with 18242 additions and 0 deletions

129
shadowsocks-libev/Makefile Normal file
View File

@ -0,0 +1,129 @@
#
# Copyright (C) 2017-2020 Yousong Zhou <yszhou4tech@gmail.com>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
# Checklist when bumping versions
#
# - update cipher list by checking src/crypto.c:crypto_init()
# - check if default mode has changed from being tcp_only
#
PKG_NAME:=shadowsocks-libev
PKG_VERSION:=3.3.5
PKG_RELEASE:=9
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/shadowsocks/shadowsocks-libev/releases/download/v$(PKG_VERSION)
PKG_HASH:=cfc8eded35360f4b67e18dc447b0c00cddb29cc57a3cec48b135e5fb87433488
PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com>
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE
PKG_FIXUP:=autoreconf
PKG_INSTALL:=1
PKG_BUILD_FLAGS:=no-mips16 lto
PKG_BUILD_PARALLEL:=1
PKG_BUILD_DEPENDS:=c-ares pcre
include $(INCLUDE_DIR)/package.mk
define Package/shadowsocks-libev-config
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev config scripts
URL:=https://github.com/shadowsocks/shadowsocks-libev
endef
define Package/shadowsocks-libev-config/conffiles
/etc/config/shadowsocks-libev
endef
define Package/shadowsocks-libev-config/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/shadowsocks-libev.config $(1)/etc/config/shadowsocks-libev
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/shadowsocks-libev.init $(1)/etc/init.d/shadowsocks-libev
endef
define Package/shadowsocks-libev/Default
define Package/shadowsocks-libev-$(1)
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev $(1)
URL:=https://github.com/shadowsocks/shadowsocks-libev
DEPENDS:=+libev +libmbedtls +libpthread +libsodium +shadowsocks-libev-config $(DEPENDS_$(1))
endef
define Package/shadowsocks-libev-$(1)/install
$$(INSTALL_DIR) $$(1)/usr/bin
$$(INSTALL_BIN) $$(PKG_INSTALL_DIR)/usr/bin/$(1) $$(1)/usr/bin
endef
endef
DEPENDS_ss-local = +libpcre
DEPENDS_ss-server = +libcares +libpcre
SHADOWSOCKS_COMPONENTS:=ss-local ss-redir ss-tunnel ss-server
define shadowsocks-libev/templates
$(foreach component,$(SHADOWSOCKS_COMPONENTS),
$(call Package/shadowsocks-libev/Default,$(component))
)
endef
$(eval $(call shadowsocks-libev/templates))
define Package/shadowsocks-libev-ss-rules
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-libev ss-rules
URL:=https://github.com/shadowsocks/shadowsocks-libev
DEPENDS:=+firewall4 \
+ip \
+resolveip \
+ucode \
+ucode-mod-fs \
+shadowsocks-libev-ss-redir \
+shadowsocks-libev-config \
+kmod-nft-tproxy
endef
define Package/shadowsocks-libev-ss-rules/install
$(INSTALL_DIR) $(1)/usr/share/ss-rules
$(INSTALL_DATA) ./files/ss-rules/* $(1)/usr/share/ss-rules/
endef
define Build/Prepare
$(call Build/Prepare/Default)
$(FIND) $(PKG_BUILD_DIR) \
-name '*.o' \
-o -name '*.lo' \
-o -name '.deps' \
-o -name '.libs' \
| $(XARGS) rm -rvf
endef
CONFIGURE_ARGS += \
--disable-documentation \
--disable-silent-rules \
--disable-assert \
--disable-ssp \
TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed
$(eval $(call BuildPackage,shadowsocks-libev-config))
$(eval $(call BuildPackage,shadowsocks-libev-ss-rules))
$(foreach component,$(SHADOWSOCKS_COMPONENTS), \
$(eval $(call BuildPackage,shadowsocks-libev-$(component))) \
)

185
shadowsocks-libev/README.md Normal file
View File

@ -0,0 +1,185 @@
Skip to [recipes](#recipes) for quick setup instructions
# components
`ss-local` provides SOCKS5 proxy with UDP associate support.
socks5 ss plain
--------> tcp:local_address:local_port ----> ss server -------> dest
`ss-redir`. The REDIRECT and TPROXY part are to be provided by `ss-rules` script. REDIRECT is for tcp traffic (`SO_ORIGINAL_DST` only supports TCP). TPROXY is for udp messages, but it's only available in the PREROUTING chain and as such cannot proxy local out traffic.
plain plain ss plain
---------> REDIRECT ------> tcp:local_address:local_port ----> ss server -----> original dest
plain plain ss plain
---------> TPROXY -------> udp:local_address:local_port -----> ss server -----> original dest
`ss-tunnel` provides ssh `-L` local-forwarding-like tunnel. Typically it's used to tunnel DNS traffic to the remote.
plain ss plain
---------> tcp|udp:local_address:local_port ------> ss server -------> tunnel_address
`ss-server`, the "ss server" in the above diagram
# uci
Option names are the same as those used in json config files. Check `validate_xxx` func definition of the [service script](files/shadowsocks-libev.init) and shadowsocks-libev's own documentation for supported options and expected value types. A [sample config file](files/shadowsocks-libev.config) is also provided for reference.
Every section have a `disabled` option to temporarily turn off the component instance or component instances referring to it.
Section type `server` is for definition of remote shadowsocks servers. They will be referred to from other component sections and as such should be named (as compared to anonymous section).
Section type `ss_local`, `ss_redir`, `ss_tunnel` are for specification of shadowsocks-libev components. They share mostly a common set of options like `local_port`, `verbose`, `fast_open`, `timeout`, etc.
Plugin options should be specified in `server` section and will be inherited by other compoenents referring to it.
We can have multiple instances of component and `server` sections. The relationship between them is many-to-one. This will have the following implications
- It's possible to have both `ss_local` and `ss_redir` referring to the same `server` definition
- It's possible to have multiple instances of `ss_redir` listening on the same address:port with `reuse_port` enabled referring to the same or different `server` sections
`ss_rules` section is for configuring the behaviour of `ss-rules` script. There can only exist at most one such section with the name also being `ss_rules`
redir_tcp name of ss_redir section with mode tcp_only or tcp_and_udp
redir_udp name of ss_redir section with mode udp_only or tcp_and_udp
ifnames only apply rules on packets from these ifnames
--- for incoming packets having source address in
src_ips_bypass will bypass the redir chain
src_ips_forward will always go through the redir chain
src_ips_checkdst will continue to have their destination addresses checked
--- otherwise, the default action can be specified with
src_default bypass, forward, [checkdst]
--- if the previous check result is checkdst,
--- then packets having destination address in
dst_ips_bypass_file
dst_ips_bypass will bypass the redir chain
dst_ips_forward_file
dst_ips_forward will go through the redir chain
--- otherwise, the default action can be specified with
dst_default [bypass], forward
--- for local out tcp packets, the default action can be specified with
local_default [bypass], forward, checkdst
ss-rules now uses nft set for storing addresses/networks. Those set names are also part of the API and can be populated by other programs, e.g. dnsmasq with builtin nft set support. Note that while nftables set supports storing cidr networks when `interval` flag is on, it rejects elements with overlaping intervals.
Extra nftables expressions can be specified with `nft_tcp_extra` and `nft_udp_extra` to apply ss_rules only to selected tcp/udp traffics. E.g. `tcp dport { 80, 443 }`, `udp dport 53`, etc.
# incompatible changes
| Commit date | Commit ID | Subject | Comment |
| ----------- | --------- | ------- | ------- |
| 2022-03-01 | fdaf2de2a | shadowsocks-libev: ss-rules: convert to using nft | ss-rules now uses nftables. UCI option ipt_args and dst_forward_recentrst are now deprecated and removed |
| 2020-08-03 | 7d7cbae75 | shadowsocks-libev: support ss-server option local_address_{v4,v6} | ss_server bind_address now deprecated, use local_address |
| 2019-05-09 | afe7d3424 | shadowsocks-libev: move plugin options to server section | This is a revision against c19e949 committed 2019-05-06 |
| 2017-07-02 | b61af9703 | shadowsocks-libev: rewrite | Packaging of shadowsocks-libev was rewritten from scratch |
# notes and faq
Useful paths and commands for debugging
# check current running status
ubus call service list '{"name": "shadowsocks-libev"}'
ubus call service list '{"name": "shadowsocks-libev", "verbose": true}'
# dump validate definition
ubus call service validate '{"package": "shadowsocks-libev"}'
ubus call service validate '{"package": "shadowsocks-libev"}' \
| jsonfilter -e '$["shadowsocks-libev"]["ss_tunnel"]'
# check json config
ls -l /var/etc/shadowsocks-libev/
# set uci config option verbose to 1, restart the service and follow the log
logread -f
ss-redir needs to open a new socket and setsockopt IP_TRANSPARENT when sending udp reply to client. This requires `CAP_NET_ADMIN` and as such the process cannot run as `nobody`
ss-local, ss-redir, etc. supports specifying an array of remote ss server, but supporting this in uci seems to be overkill. The workaround can be defining multiple `server` sections and multiple `ss-redir` instances with `reuse_port` enabled
# recipes
## forward all
This will setup firewall rules to forward almost all incoming tcp/udp and locally generated tcp traffic (excluding those to private addresses like 192.168.0.0/16 etc.) through remote shadowsocks server
Install components.
Retry each command till it succeed
opkg install shadowsocks-libev-ss-redir
opkg install shadowsocks-libev-ss-rules
opkg install shadowsocks-libev-ss-tunnel
Edit uci config `/etc/config/shadowsocks-libev`.
Replace `config server 'sss0'` section with parameters of your own remote shadowsocks server.
As for other options, change them only when you know the effect.
config server 'sss0'
option disabled 0
option server '_sss_addr_'
option server_port '_sss_port_'
option password '********'
option method 'aes-256-cfb'
config ss_tunnel
option disabled 0
option server 'sss0'
option local_address '0.0.0.0'
option local_port '8053'
option tunnel_address '8.8.8.8:53'
option mode 'tcp_and_udp'
config ss_redir ssr0
option disabled 0
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1100'
option mode 'tcp_and_udp'
option reuse_port 1
config ss_rules 'ss_rules'
option disabled 0
option redir_tcp 'ssr0'
option redir_udp 'ssr0'
option src_default 'checkdst'
option dst_default 'forward'
option local_default 'forward'
Restart shadowsocks-libev components
/etc/init.d/shadowsocks-libev restart
Check if things are in place
nft list ruleset | sed -r -n '/^\t[a-z]+ ss_rules[^ ]+ \{/,/^\t\}/p'
netstat -lntp | grep -E '8053|1100'
ps ww | grep ss-
Edit `/etc/config/dhcp`, making sure options are present in the first dnsmasq section like the following to let it use local tunnel endpoint for upstream dns query.
Option `noresolv` instructs dnsmasq to not use other dns servers like advertised by local isp.
Option `localuse` intends to make sure the device you are configuring also uses this dnsmasq instance as the resolver, not the ones from other sources.
config dnsmasq
...
list server '127.0.0.1#8053'
option noresolv 1
option localuse 1
Restart dnsmasq
/etc/init.d/dnsmasq restart
Check network on your computer
nslookup www.google.com
curl -vv https://www.google.com

View File

@ -0,0 +1,60 @@
config ss_local
option disabled 1
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1080'
option timeout '30'
config ss_tunnel
option disabled 1
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1090'
option tunnel_address 'example.com:80'
option mode 'tcp_and_udp'
option timeout '60'
config ss_redir hi
option disabled 1
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1100'
option mode 'tcp_and_udp'
option timeout '60'
option fast_open 1
option verbose 1
option reuse_port 1
config ss_redir hj
option disabled 1
option server 'sss0'
option local_address '0.0.0.0'
option local_port '1100'
option mode 'tcp_and_udp'
option timeout '60'
option fast_open 1
option verbose 1
option reuse_port 1
config ss_rules 'ss_rules'
option disabled 1
option redir_tcp 'hi'
option redir_udp 'hi'
option src_default 'checkdst'
option dst_default 'bypass'
option local_default 'checkdst'
list src_ips_forward '192.168.1.4'
list dst_ips_forward '8.8.8.8'
config server 'sss0'
option disabled 1
option server '192.168.1.3'
option server_port '9001'
option password '********'
option method 'aes-256-cfb'
config ss_server
option disabled 1
option server_port '9001'
option password '********'
option method 'aes-256-cfb'

View File

@ -0,0 +1,320 @@
#!/bin/sh /etc/rc.common
#
# Copyright (C) 2017-2019 Yousong Zhou <yszhou4tech@gmail.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
USE_PROCD=1
START=99
ss_confdir=/var/etc/shadowsocks-libev
ss_bindir=/usr/bin
ssrules_uc="/usr/share/ss-rules/ss-rules.uc"
ssrules_nft="/etc/nftables.d/90-ss-rules.nft"
ss_mkjson_server_conf() {
local cfgserver
config_get cfgserver "$cfg" server
[ -n "$cfgserver" ] || return 1
eval "$(validate_server_section "$cfg" ss_validate_mklocal)"
validate_server_section "$cfgserver" || return 1
[ "$disabled" = 0 ] || return 1
ss_mkjson_server_conf_ "$cfgserver"
}
ss_mkjson_server_conf_() {
[ -n "$server_port" ] || return 1
[ -z "$server" ] || json_add_string server "$server"
json_add_int server_port "$server_port"
[ -z "$method" ] || json_add_string method "$method"
[ -z "$key" ] || json_add_string key "$key"
[ -z "$password" ] || json_add_string password "$password"
[ -z "$plugin" ] || json_add_string plugin "$plugin"
[ -z "$plugin_opts" ] || json_add_string plugin_opts "$plugin_opts"
}
ss_mkjson_ss_local_conf() {
ss_mkjson_server_conf
}
ss_mkjson_ss_redir_conf() {
ss_mkjson_server_conf
}
ss_mkjson_ss_server_conf() {
ss_mkjson_server_conf_
}
ss_mkjson_ss_tunnel_conf() {
ss_mkjson_server_conf || return 1
[ -n "$tunnel_address" ] || return 1
json_add_string tunnel_address "$tunnel_address"
}
ss_xxx() {
local cfg="$1"
local cfgtype="$2"
local bin="$ss_bindir/${cfgtype/_/-}"
local confjson="$ss_confdir/$cfgtype.$cfg.json"
[ -x "$bin" ] || return
eval "$("validate_${cfgtype}_section" "$cfg" ss_validate_mklocal)"
"validate_${cfgtype}_section" "$cfg" || return
[ "$disabled" = 0 ] || return
json_init
ss_mkjson_${cfgtype}_conf || return
json_add_boolean use_syslog 1
json_add_boolean ipv6_first "$ipv6_first"
json_add_boolean fast_open "$fast_open"
json_add_boolean reuse_port "$reuse_port"
json_add_boolean no_delay "$no_delay"
[ -z "$local_address" ] || json_add_string local_address "$local_address"
[ -z "$local_port" ] || json_add_int local_port "$local_port"
[ -z "$local_ipv4_address" ] || json_add_string local_ipv4_address "$local_ipv4_address"
[ -z "$local_ipv6_address" ] || json_add_string local_ipv6_address "$local_ipv6_address"
[ -z "$mode" ] || json_add_string mode "$mode"
[ -z "$mtu" ] || json_add_int mtu "$mtu"
[ -z "$timeout" ] || json_add_int timeout "$timeout"
[ -z "$user" ] || json_add_string user "$user"
[ -z "$acl" ] || json_add_string acl "$acl"
json_dump -i >"$confjson"
procd_open_instance "$cfgtype.$cfg"
procd_set_param command "$bin" -c "$confjson"
[ "$verbose" = 0 ] || procd_append_param command -v
if [ -n "$bind_address" ]; then
echo "$cfgtype $cfg: uci option bind_address deprecated, please switch to local_address" >&2
procd_append_param command -b "$bind_address"
fi
procd_set_param file "$confjson"
procd_set_param respawn
procd_close_instance
ss_rules_cb
}
ss_rules_cb() {
local cfgserver server
if [ "$cfgtype" = ss_redir ]; then
config_get cfgserver "$cfg" server
config_get server "$cfgserver" server
ss_redir_servers="$ss_redir_servers $server"
if [ "$mode" = tcp_only -o "$mode" = "tcp_and_udp" ]; then
eval "ss_rules_redir_tcp_$cfg=$local_port"
fi
if [ "$mode" = udp_only -o "$mode" = "tcp_and_udp" ]; then
eval "ss_rules_redir_udp_$cfg=$local_port"
fi
fi
}
ss_rules_nft_gen() {
local cfg="ss_rules"
local cfgtype
local local_port_tcp local_port_udp
local remote_servers
[ -s "$ssrules_uc" ] || return 1
config_get cfgtype "$cfg" TYPE
[ "$cfgtype" = ss_rules ] || return 1
eval "$(validate_ss_rules_section "$cfg" ss_validate_mklocal)"
validate_ss_rules_section "$cfg" || return 1
[ "$disabled" = 0 ] || return 2
eval local_port_tcp="\$ss_rules_redir_tcp_$redir_tcp"
eval local_port_udp="\$ss_rules_redir_udp_$redir_udp"
[ -n "$local_port_tcp" -o -n "$local_port_udp" ] || return 1
remote_servers="$(echo $ss_redir_servers \
| tr ' ' '\n' \
| sort -u \
| xargs -n 1 resolveip \
| sort -u)"
local tmp="/tmp/ssrules"
json_init
json_add_string o_remote_servers "$remote_servers"
json_add_int o_redir_tcp_port "$local_port_tcp"
json_add_int o_redir_udp_port "$local_port_udp"
json_add_string o_ifnames "$ifnames"
json_add_string o_local_default "$local_default"
json_add_string o_src_bypass "$src_ips_bypass"
json_add_string o_src_forward "$src_ips_forward"
json_add_string o_src_checkdst "$src_ips_checkdst"
json_add_string o_src_default "$src_default"
json_add_string o_dst_bypass "$dst_ips_bypass"
json_add_string o_dst_forward "$dst_ips_forward"
json_add_string o_dst_bypass_file "$dst_ips_bypass_file"
json_add_string o_dst_forward_file "$dst_ips_forward_file"
json_add_string o_dst_default "$dst_default"
json_add_string o_nft_tcp_extra "$nft_tcp_extra"
json_add_string o_nft_udp_extra "$nft_udp_extra"
json_dump -i >"$tmp.json"
if utpl -S -F "$tmp.json" "$ssrules_uc" >"$tmp.nft" \
&& ! cmp -s "$tmp.nft" "$ssrules_nft"; then
echo "table inet chk {include \"$tmp.nft\";}" >"$tmp.nft.chk"
if nft -f "$tmp.nft.chk" -c; then
mv "$tmp.nft" "$ssrules_nft"
fw4 restart
fi
rm -f "$tmp.nft.chk"
fi
rm -f "$tmp.json"
rm -f "$tmp.nft"
}
ss_rules_nft_reset() {
if [ -f "$ssrules_nft" ]; then
rm -f "$ssrules_nft"
fw4 restart
fi
}
ss_rules() {
if ! ss_rules_nft_gen; then
ss_rules_nft_reset
fi
}
start_service() {
local cfgtype
mkdir -p "$ss_confdir"
config_load shadowsocks-libev
for cfgtype in ss_local ss_redir ss_server ss_tunnel; do
config_foreach ss_xxx "$cfgtype" "$cfgtype"
done
ss_rules
}
stop_service() {
ss_rules_nft_reset
rm -rf "$ss_confdir"
}
service_triggers() {
procd_add_reload_interface_trigger wan
procd_add_reload_trigger shadowsocks-libev
procd_open_validate
validate_server_section
validate_ss_local_section
validate_ss_redir_section
validate_ss_rules_section
validate_ss_server_section
validate_ss_tunnel_section
procd_close_validate
}
ss_validate_mklocal() {
local tuple opts
shift 2
for tuple in "$@"; do
opts="${tuple%%:*} $opts"
done
[ -z "$opts" ] || echo "local $opts"
}
ss_validate() {
uci_validate_section shadowsocks-libev "$@"
}
validate_common_server_options_() {
local cfgtype="$1"; shift
local cfg="$1"; shift
local func="$1"; shift
local stream_methods='"table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20", "chacha20-ietf"'
local aead_methods='"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305"'
"${func:-ss_validate}" "$cfgtype" "$cfg" "$@" \
'disabled:bool:0' \
'server:host' \
'server_port:port' \
'password:string' \
'key:string' \
"method:or($stream_methods, $aead_methods)" \
'plugin:string' \
'plugin_opts:string'
}
validate_common_client_options_() {
validate_common_options_ "$@" \
'server:uci("shadowsocks-libev", "@server")' \
'local_address:ipaddr:0.0.0.0' \
'local_port:port'
}
validate_common_options_() {
local cfgtype="$1"; shift
local cfg="$1"; shift
local func="$1"; shift
"${func:-ss_validate}" "$cfgtype" "$cfg" "$@" \
'disabled:bool:0' \
'fast_open:bool:0' \
'ipv6_first:bool:0' \
'no_delay:bool:0' \
'reuse_port:bool:0' \
'verbose:bool:0' \
'mode:or("tcp_only", "udp_only", "tcp_and_udp"):tcp_only' \
'mtu:uinteger' \
'timeout:uinteger' \
'user:string'
}
validate_server_section() {
validate_common_server_options_ server "$1" "$2"
}
validate_ss_local_section() {
validate_common_client_options_ ss_local "$1" "$2" \
'acl:file'
}
validate_ss_redir_section() {
validate_common_client_options_ ss_redir "$1" "$2"
}
validate_ss_rules_section() {
"${2:-ss_validate}" ss_rules "$1" \
'disabled:bool:0' \
'redir_tcp:uci("shadowsocks-libev", "@ss_redir")' \
'redir_udp:uci("shadowsocks-libev", "@ss_redir")' \
'src_ips_bypass:or(ipaddr,cidr)' \
'src_ips_forward:or(ipaddr,cidr)' \
'src_ips_checkdst:or(ipaddr,cidr)' \
'dst_ips_bypass_file:file' \
'dst_ips_bypass:or(ipaddr,cidr)' \
'dst_ips_forward_file:file' \
'dst_ips_forward:or(ipaddr,cidr)' \
'src_default:or("bypass", "forward", "checkdst"):checkdst' \
'dst_default:or("bypass", "forward"):bypass' \
'local_default:or("bypass", "forward", "checkdst"):bypass' \
'nft_tcp_extra:string' \
'nft_udp_extra:string' \
'ifnames:maxlength(15)'
}
validate_ss_server_section() {
validate_common_server_options_ ss_server "$1" \
validate_common_options_ \
"$2" \
'local_address:ipaddr' \
'local_ipv4_address:ip4addr' \
'local_ipv6_address:ip6addr' \
'bind_address:ipaddr' \
'acl:file'
}
validate_ss_tunnel_section() {
validate_common_client_options_ ss_tunnel "$1" \
"$2" \
'tunnel_address:regex(".+\:[0-9]+")'
}

View File

@ -0,0 +1,122 @@
{%
function get_local_verdict() {
let v = o_local_default;
if (v == "checkdst") {
return "goto ss_rules_dst_" + proto;
} else if (v == "forward") {
return "goto ss_rules_forward_" + proto;
} else {
return null;
}
}
function get_src_default_verdict() {
let v = o_src_default;
if (v == "checkdst") {
return "goto ss_rules_dst_" + proto;
} else if (v == "forward") {
return "goto ss_rules_forward_" + proto;
} else {
return "accept";
}
}
function get_dst_default_verdict() {
let v = o_dst_default;
if (v == "forward") {
return "goto ss_rules_forward_" + proto;
} else {
return "accept";
}
}
function get_ifnames() {
let res = [];
for (let ifname in split(o_ifnames, /[ \t\n]/)) {
ifname = trim(ifname);
if (ifname) push(res, ifname);
}
return res;
}
let type, hook, priority, redir_port;
if (proto == "tcp") {
type = "nat";
hook = "prerouting";
priority = -1;
redir_port = o_redir_tcp_port;
} else if (proto == "udp") {
type = "filter";
hook = "prerouting";
priority = "mangle";
redir_port = o_redir_udp_port;
if (system("
set -o errexit
iprr() {
while ip $1 rule del fwmark 1 lookup 100 2>/dev/null; do true; done
ip $1 rule add fwmark 1 lookup 100
ip $1 route flush table 100 2>/dev/null || true
ip $1 route add local default dev lo table 100
}
iprr -4
iprr -6
") != 0) {
return ;
}
} else {
return;
}
%}
{% if (redir_port): %}
chain ss_rules_pre_{{ proto }} {
type {{ type }} hook {{ hook }} priority {{ priority }};
meta l4proto {{ proto }}{%- let ifnames=get_ifnames(); if (length(ifnames)): %} iifname { {{join(", ", ifnames)}} }{% endif %} goto ss_rules_pre_src_{{ proto }};
}
chain ss_rules_pre_src_{{ proto }} {
ip daddr @ss_rules_dst_bypass_ accept;
ip6 daddr @ss_rules6_dst_bypass_ accept;
goto ss_rules_src_{{ proto }};
}
chain ss_rules_src_{{ proto }} {
ip saddr @ss_rules_src_bypass accept;
ip saddr @ss_rules_src_forward goto ss_rules_forward_{{ proto }};
ip saddr @ss_rules_src_checkdst goto ss_rules_dst_{{ proto }};
ip6 saddr @ss_rules6_src_bypass accept;
ip6 saddr @ss_rules6_src_forward goto ss_rules_forward_{{ proto }};
ip6 saddr @ss_rules6_src_checkdst goto ss_rules_dst_{{ proto }};
{{ get_src_default_verdict() }};
}
chain ss_rules_dst_{{ proto }} {
ip daddr @ss_rules_dst_bypass accept;
ip daddr @ss_rules_dst_forward goto ss_rules_forward_{{ proto }};
ip6 daddr @ss_rules6_dst_bypass accept;
ip6 daddr @ss_rules6_dst_forward goto ss_rules_forward_{{ proto }};
{{ get_dst_default_verdict() }};
}
{% if (proto == "tcp"): %}
chain ss_rules_forward_{{ proto }} {
meta l4proto tcp {{ o_nft_tcp_extra }} redirect to :{{ redir_port }};
}
{% let local_verdict = get_local_verdict(); if (local_verdict): %}
chain ss_rules_local_out {
type {{ type }} hook output priority -1;
meta l4proto != tcp accept;
ip daddr @ss_rules_dst_bypass_ accept;
ip daddr @ss_rules_dst_bypass accept;
ip6 daddr @ss_rules6_dst_bypass_ accept;
ip6 daddr @ss_rules6_dst_bypass accept;
{{ local_verdict }};
}
{% endif %}
{% elif (proto == "udp"): %}
chain ss_rules_forward_{{ proto }} {
meta l4proto udp {{ o_nft_udp_extra }} meta mark set 1 tproxy to :{{ redir_port }};
}
{% endif %}
{% endif %}

View File

@ -0,0 +1,114 @@
{%
let fs = require("fs");
let o_dst_bypass4_ = "
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
169.254.0.0/16
172.16.0.0/12
192.0.0.0/24
192.0.2.0/24
192.31.196.0/24
192.52.193.0/24
192.88.99.0/24
192.168.0.0/16
192.175.48.0/24
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
224.0.0.0/4
240.0.0.0/4
";
let o_dst_bypass6_ = "
::1/128
::/128
::ffff:0:0/96
64:ff9b:1::/48
100::/64
fe80::/10
2001::/23
fc00::/7
";
let o_dst_bypass_ = o_dst_bypass4_ + " " + o_dst_bypass6_;
let set_suffix = {
"src_bypass": {
str: o_src_bypass,
},
"src_forward": {
str: o_src_forward,
},
"src_checkdst": {
str: o_src_checkdst,
},
"dst_bypass": {
str: o_dst_bypass,
file: o_dst_bypass_file,
},
"dst_bypass_": {
str: o_dst_bypass_,
},
"dst_forward": {
str: o_dst_forward,
file: o_dst_forward_file,
},
"dst_forward_rrst_": {},
};
function set_name(suf, af) {
if (af == 4) {
return "ss_rules_"+suf;
} else {
return "ss_rules6_"+suf;
}
}
function set_elements_parse(res, str, af) {
for (let addr in split(str, /[ \t\n]/)) {
addr = trim(addr);
if (!addr) continue;
if (af == 4 && index(addr, ":") != -1) continue;
if (af == 6 && index(addr, ":") == -1) continue;
push(res, addr);
}
}
function set_elements(suf, af) {
let obj = set_suffix[suf];
let res = [];
let addr;
let str = obj["str"];
if (str) {
set_elements_parse(res, str, af);
}
let file = obj["file"];
if (file) {
let fd = fs.open(file);
if (fd) {
str = fd.read("all");
set_elements_parse(res, str, af);
}
}
return res;
}
%}
{% for (let suf in set_suffix): for (let af in [4, 6]): %}
set {{ set_name(suf, af) }} {
type ipv{{af}}_addr;
flags interval;
auto-merge;
{% let elems = set_elements(suf, af); if (length(elems)): %}
elements = {
{% for (let i = 0; i < length(elems); i++): %}
{{ elems[i] }}{% if (i < length(elems) - 1): %},{% endif %}{% print("\n") %}
{% endfor %}
}
{% endif %}
}
{% endfor; endfor %}

View File

@ -0,0 +1,8 @@
{%
include("set.uc");
include("chain.uc", {proto: "tcp"});
include("chain.uc", {proto: "udp"});
%}

85
shadowsocks-rust/Makefile Normal file
View File

@ -0,0 +1,85 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2017-2020 Yousong Zhou <yszhou4tech@gmail.com>
# Copyright (C) 2021 ImmortalWrt.org
include $(TOPDIR)/rules.mk
PKG_NAME:=shadowsocks-rust
PKG_VERSION:=1.15.2
PKG_RELEASE:=1
PKG_SOURCE_HEADER:=shadowsocks-v$(PKG_VERSION)
PKG_SOURCE_BODY:=unknown-linux-musl
PKG_SOURCE_FOOTER:=tar.xz
PKG_SOURCE_URL:=https://github.com/shadowsocks/shadowsocks-rust/releases/download/v$(PKG_VERSION)/
ifeq ($(ARCH),aarch64)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).aarch64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=97850893c5a35b68ccd419b542c1785e4c0006e8c0c0b10eac8e5b8c67b12704
else ifeq ($(ARCH),arm)
# Referred to golang/golang-values.mk
ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
ifeq ($(ARM_CPU_FEATURES),)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabi.$(PKG_SOURCE_FOOTER)
PKG_HASH:=728f4550abe4f18679555fa00b88ce889d2f412be7fa0d96bf153d086ad0c63e
else
PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabihf.$(PKG_SOURCE_FOOTER)
PKG_HASH:=f13ae6497843347c91ef8b0634cee96f5043a644b2fba30009cafd6c9e65d7df
endif
else ifeq ($(ARCH),i386)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).i686-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=a8558a9e898f9ba875136c3d038e968ca8d301a7dcde977f6483d5072f57695f
else ifeq ($(ARCH),mips)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).mips-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=a3f99d549c9f417fef63fa323840e0c4fb4dc96a53cf8329293c2a4e485ed239
else ifeq ($(ARCH),mipsel)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).mipsel-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=47d0f10d94216376057fc4238ebab68d19e3882293d5fe76ac3d29c41458a985
else ifeq ($(ARCH),x86_64)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).x86_64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=69c2df2bd4e9e2ff0d70faa14b70888de2eb205ab2a49dd7066c86363e2acc50
# Set the default value to make OpenWrt Package Checker happy
else
PKG_SOURCE:=dummy
PKG_HASH:=dummy
endif
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE
include $(INCLUDE_DIR)/package.mk
TAR_CMD:=$(HOST_TAR) -C $(PKG_BUILD_DIR) $(TAR_OPTIONS)
define Package/shadowsocks-rust/Default
define Package/shadowsocks-rust-$(1)
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocks-rust $(1)
URL:=https://github.com/shadowsocks/shadowsocks-rust
DEPENDS:=@USE_MUSL @(aarch64||arm||i386||mips||mipsel||x86_64) @!(TARGET_x86_geode||TARGET_x86_legacy)
endef
define Package/shadowsocks-rust-$(1)/install
$$(INSTALL_DIR) $$(1)/usr/bin
$$(INSTALL_BIN) $$(PKG_BUILD_DIR)/$(1) $$(1)/usr/bin
endef
endef
SHADOWSOCKS_COMPONENTS:=sslocal ssmanager ssserver ssurl ssservice
define shadowsocks-rust/templates
$(foreach component,$(SHADOWSOCKS_COMPONENTS),
$(call Package/shadowsocks-rust/Default,$(component))
)
endef
$(eval $(call shadowsocks-rust/templates))
define Build/Compile
endef
$(foreach component,$(SHADOWSOCKS_COMPONENTS), \
$(eval $(call BuildPackage,shadowsocks-rust-$(component))) \
)

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Copyright (C) 2017-2020 Yousong Zhou <yszhou4tech@gmail.com>
# Copyright (C) 2018 Lean <coolsnowwolf@gmail.com>
# Copyright (C) 2021 ImmortalWrt.org
include $(TOPDIR)/rules.mk
PKG_NAME:=shadowsocksr-libev
PKG_VERSION:=2.5.6
PKG_RELEASE:=9
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/shadowsocksrr/shadowsocksr-libev
PKG_SOURCE_DATE:=2018-03-07
PKG_SOURCE_VERSION:=d63ff863800a5645aca4309d5dd5962bd1e95543
PKG_MIRROR_HASH:=34308ed827a5dd4f4e35619914102d55b00604faa44fda051d1d25fb4a319325
PKG_LICENSE:=GPL-3.0
PKG_LICENSE_FILES:=LICENSE
PKG_FIXUP:=autoreconf
PKG_USE_MIPS16:=0
PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/shadowsocksr-libev/Default
define Package/shadowsocksr-libev-ssr-$(1)
SECTION:=net
CATEGORY:=Network
SUBMENU:=Web Servers/Proxies
TITLE:=shadowsocksr-libev ssr-$(1)
URL:=https://github.com/shadowsocksrr/shadowsocksr-libev
DEPENDS:=+libev +libsodium +libopenssl +libpthread +libpcre +libudns +zlib
endef
define Package/shadowsocksr-libev-ssr-$(1)/install
$$(INSTALL_DIR) $$(1)/usr/bin
$$(INSTALL_BIN) $$(PKG_INSTALL_DIR)/usr/bin/ss-$(1) $$(1)/usr/bin/ssr-$(1)
endef
endef
SHADOWSOCKSR_COMPONENTS:=check local nat redir server
define shadowsocksr-libev/templates
$(foreach component,$(SHADOWSOCKSR_COMPONENTS),
$(call Package/shadowsocksr-libev/Default,$(component))
)
endef
$(eval $(call shadowsocksr-libev/templates))
CONFIGURE_ARGS += \
--disable-documentation \
--disable-ssp \
--disable-assert \
--enable-system-shared-lib
TARGET_CFLAGS += -flto
TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed
$(foreach component,$(SHADOWSOCKSR_COMPONENTS), \
$(eval $(call BuildPackage,shadowsocksr-libev-ssr-$(component))) \
)

View File

@ -0,0 +1,397 @@
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ build/
.deps/
/Makefile
src/Makefile
+server/Makefile
libev/Makefile
libudns/Makefile
libcork/Makefile
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
if USE_SYSTEM_SHARED_LIB
-SUBDIRS = libcork libipset src
+SUBDIRS = libcork libipset src server
else
-SUBDIRS = libsodium libcork libipset libudns libev src
+SUBDIRS = libsodium libcork libipset libudns libev src server
endif
if ENABLE_DOCUMENTATION
--- a/Makefile.in
+++ b/Makefile.in
@@ -195,7 +195,7 @@ am__define_uniq_tagged_files = \
ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
-DIST_SUBDIRS = libsodium libcork libipset libudns libev src doc
+DIST_SUBDIRS = libsodium libcork libipset libudns libev src server doc
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(srcdir)/shadowsocks-libev.pc.in $(top_srcdir)/auto/ar-lib \
$(top_srcdir)/auto/compile $(top_srcdir)/auto/config.guess \
@@ -377,8 +377,9 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
@USE_SYSTEM_SHARED_LIB_FALSE@SUBDIRS = libsodium libcork libipset \
-@USE_SYSTEM_SHARED_LIB_FALSE@ libudns libev src $(am__append_1)
-@USE_SYSTEM_SHARED_LIB_TRUE@SUBDIRS = libcork libipset src \
+@USE_SYSTEM_SHARED_LIB_FALSE@ libudns libev src server \
+@USE_SYSTEM_SHARED_LIB_FALSE@ $(am__append_1)
+@USE_SYSTEM_SHARED_LIB_TRUE@SUBDIRS = libcork libipset src server \
@USE_SYSTEM_SHARED_LIB_TRUE@ $(am__append_1)
ACLOCAL_AMFLAGS = -I m4
pkgconfiglibdir = $(libdir)/pkgconfig
--- a/configure
+++ b/configure
@@ -649,7 +649,6 @@ PTHREAD_CC
ax_pthread_config
INET_NTOP_LIB
MV
-RM
GZIP
XMLTO
ASCIIDOC
@@ -757,6 +756,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -857,6 +857,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1109,6 +1110,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1246,7 +1256,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1399,6 +1409,7 @@ Fine tuning of the installation director
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -2472,8 +2483,8 @@ ac_configure="$SHELL $ac_aux_dir/configu
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
@@ -3783,7 +3794,7 @@ $as_echo "$ac_cv_safe_to_define___extens
-am__api_version='1.14'
+am__api_version='1.15'
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -3972,7 +3983,7 @@ else
$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
fi
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -4363,8 +4374,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}ma
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
mkdir_p='$(MKDIR_P)'
-# We need awk for the "check" target. The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AMTAR='$${TAR-tar}'
@@ -4549,6 +4560,7 @@ END
as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
fi
fi
+
if test -n "$ac_tool_prefix"; then
for ac_prog in ar lib "link -lib"
do
@@ -12494,47 +12506,6 @@ $as_echo "no" >&6; }
fi
- # Extract the first word of "rm", so it can be a program name with args.
-set dummy rm; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_RM+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $RM in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_RM="$RM" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- test -z "$ac_cv_path_RM" && ac_cv_path_RM="rm"
- ;;
-esac
-fi
-RM=$ac_cv_path_RM
-if test -n "$RM"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5
-$as_echo "$RM" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
# Extract the first word of "mv", so it can be a program name with args.
set dummy mv; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -16204,15 +16175,162 @@ $as_echo "#define HAVE_IPv6 1" >>confdef
if test -z "$USE_SYSTEM_SHARED_LIB_TRUE"; then :
- else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sodium_init in -lsodium" >&5
+$as_echo_n "checking for sodium_init in -lsodium... " >&6; }
+if ${ac_cv_lib_sodium_sodium_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsodium $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sodium_init ();
+int
+main ()
+{
+return sodium_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_sodium_sodium_init=yes
+else
+ ac_cv_lib_sodium_sodium_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sodium_sodium_init" >&5
+$as_echo "$ac_cv_lib_sodium_sodium_init" >&6; }
+if test "x$ac_cv_lib_sodium_sodium_init" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSODIUM 1
+_ACEOF
+
+ LIBS="-lsodium $LIBS"
+
+else
+
+ as_fn_error $? "Couldn't find libsodium. Try installing libsodium-dev[el]." "$LINENO" 5
+
+fi
+
+
+else
subdirs="$subdirs libsodium"
fi
-ac_config_files="$ac_config_files shadowsocks-libev.pc Makefile libcork/Makefile libipset/Makefile src/Makefile"
+ac_config_files="$ac_config_files shadowsocks-libev.pc Makefile libcork/Makefile libipset/Makefile src/Makefile server/Makefile"
if test -z "$USE_SYSTEM_SHARED_LIB_TRUE"; then :
- else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dns_dnlen in -ludns" >&5
+$as_echo_n "checking for dns_dnlen in -ludns... " >&6; }
+if ${ac_cv_lib_udns_dns_dnlen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ludns $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dns_dnlen ();
+int
+main ()
+{
+return dns_dnlen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_udns_dns_dnlen=yes
+else
+ ac_cv_lib_udns_dns_dnlen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_udns_dns_dnlen" >&5
+$as_echo "$ac_cv_lib_udns_dns_dnlen" >&6; }
+if test "x$ac_cv_lib_udns_dns_dnlen" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBUDNS 1
+_ACEOF
+
+ LIBS="-ludns $LIBS"
+
+else
+ as_fn_error $? "Couldn't find libudns. Try installing libudns-dev or udns-devel." "$LINENO" 5
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ev_loop_destroy in -lev" >&5
+$as_echo_n "checking for ev_loop_destroy in -lev... " >&6; }
+if ${ac_cv_lib_ev_ev_loop_destroy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lev $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ev_loop_destroy ();
+int
+main ()
+{
+return ev_loop_destroy ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ev_ev_loop_destroy=yes
+else
+ ac_cv_lib_ev_ev_loop_destroy=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ev_ev_loop_destroy" >&5
+$as_echo "$ac_cv_lib_ev_ev_loop_destroy" >&6; }
+if test "x$ac_cv_lib_ev_ev_loop_destroy" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBEV 1
+_ACEOF
+
+ LIBS="-lev $LIBS"
+
+else
+ as_fn_error $? "Couldn't find libev. Try installing libev-dev[el]." "$LINENO" 5
+fi
+
+
+else
ac_config_files="$ac_config_files libudns/Makefile libev/Makefile"
fi
@@ -17258,6 +17376,7 @@ do
"libcork/Makefile") CONFIG_FILES="$CONFIG_FILES libcork/Makefile" ;;
"libipset/Makefile") CONFIG_FILES="$CONFIG_FILES libipset/Makefile" ;;
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "server/Makefile") CONFIG_FILES="$CONFIG_FILES server/Makefile" ;;
"libudns/Makefile") CONFIG_FILES="$CONFIG_FILES libudns/Makefile" ;;
"libev/Makefile") CONFIG_FILES="$CONFIG_FILES libev/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
@@ -17958,8 +18077,8 @@ $as_echo X"$file" |
fi
cfgfile="${ofile}T"
- trap "$RM -f \"$cfgfile\"; exit 1" 1 2 15
- $RM -f "$cfgfile"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
--- a/configure.ac
+++ b/configure.ac
@@ -315,7 +315,8 @@ AC_CONFIG_FILES([ shadowsocks-libev.pc
Makefile
libcork/Makefile
libipset/Makefile
- src/Makefile])
+ src/Makefile
+ server/Makefile])
AM_COND_IF([USE_SYSTEM_SHARED_LIB],[
AC_CHECK_LIB([udns], [dns_dnlen], ,[AC_MSG_ERROR([Couldn't find libudns. Try installing libudns-dev or udns-devel.])])
AC_CHECK_LIB([ev], [ev_loop_destroy], ,[AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])])

View File

@ -0,0 +1,20 @@
--- a/src/obfs/obfs.c
+++ b/src/obfs/obfs.c
@@ -88,7 +88,7 @@ obfs_class *new_obfs_class(const char *p
plugin->client_decode = tls12_ticket_auth_client_decode;
return plugin;
- /*} else if (strcmp(plugin_name, "verify_simple") == 0) {
+ } else if (strcmp(plugin_name, "verify_simple") == 0) {
obfs_class * plugin = (obfs_class*)malloc(sizeof(obfs_class));
plugin->init_data = init_data;
plugin->new_obfs = verify_simple_new_obfs;
@@ -115,7 +115,7 @@ obfs_class *new_obfs_class(const char *p
plugin->client_udp_pre_encrypt = NULL;
plugin->client_udp_post_decrypt = NULL;
- return plugin;*/
+ return plugin;
} else if (strcmp(plugin_name, "auth_sha1") == 0) {
obfs_class *plugin = (obfs_class *) malloc(sizeof(obfs_class));
plugin->init_data = auth_simple_init_data;

View File

@ -0,0 +1,37 @@
--- a/src/utils.c
+++ b/src/utils.c
@@ -258,8 +258,6 @@ usage()
{
printf("\n");
printf("shadowsocks-libev %s with %s\n\n", VERSION, USING_CRYPTO);
- printf(
- " maintained by Max Lv <max.c.lv@gmail.com> and Linus Yang <laokongzi@gmail.com>\n\n");
printf(" usage:\n\n");
#ifdef MODULE_LOCAL
printf(" ss-local\n");
@@ -299,6 +297,25 @@ usage()
" The default cipher is rc4-md5.\n");
printf("\n");
printf(
+ " -o <obfs> Obfs of your remote server: plain,\n");
+ printf(
+ " http_simple, http_post and tls1.2_ticket_auth.\n");
+ printf(
+ " -g <obfs-param> Obfs-Param of your remote server.\n");
+ printf(
+ " -O <protocol> Protocol of your remote server: origin,\n");
+ printf(
+ " auth_sha1, auth_sha1_v2, auth_sha1_v4,\n");
+ printf(
+ " auth_aes128_md5, auth_aes128_sha1,\n");
+ printf(
+ " auth_chain_a, auth_chain_b, auth_chain_c,\n");
+ printf(
+ " auth_chain_d, auth_chain_e and auth_chain_f.\n");
+ printf(
+ " -G <protocol-param> Protocol-Param of your remote server.\n");
+ printf("\n");
+ printf(
" [-a <user>] Run as another user.\n");
printf(
" [-f <pid_file>] The file path to store pid.\n");

View File

@ -0,0 +1,20 @@
--- a/src/http.h
+++ b/src/http.h
@@ -29,6 +29,6 @@
#include <stdio.h>
#include "protocol.h"
-const protocol_t *const http_protocol;
+extern const protocol_t *const http_protocol;
#endif
--- a/src/tls.h
+++ b/src/tls.h
@@ -28,6 +28,6 @@
#include "protocol.h"
-const protocol_t *const tls_protocol;
+extern const protocol_t *const tls_protocol;
#endif

View File

@ -0,0 +1,11 @@
--- a/src/local.c
+++ b/src/local.c
@@ -718,7 +718,7 @@ server_recv_cb(EV_P_ ev_io *w, int reven
ss_free(hostname);
} else {
- strncpy(host, ip, sizeof(ip));
+ strncpy(host, ip, INET6_ADDRSTRLEN);
}
}

View File

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

View File

@ -0,0 +1,154 @@
--- a/completions/bash/ss-redir
+++ b/completions/bash/ss-redir
@@ -2,7 +2,7 @@ _ss_redir()
{
local cur prev opts ciphers
ciphers='rc4-md5 table rc4 aes-128-cfb aes-192-cfb aes-256-cfb aes-128-ctr aes-192-ctr aes-256-ctr bf-cfb camellia-128-cfb camellia-192-cfb camellia-256-cfb cast5-cfb des-cfb idea-cfb rc2-cfb seed-cfb salsa20 chacha20 and chacha20-ietf'
- opts='-s -b -p -k -f -t -m -c -a -n -u -U -v -h -A --mtu --help --mptcp -l'
+ opts='-s -b -p -k -f -t -m -c -a -n -u -U -T -v -h -A --mtu --help --mptcp -l'
cur=${COMP_WORDS[COMP_CWORD]}
prev="${COMP_WORDS[COMP_CWORD-1]}"
case "$prev" in
--- a/src/jconf.c
+++ b/src/jconf.c
@@ -338,7 +338,11 @@ read_jconf(const char *file)
check_json_value_type(value, json_boolean,
"invalid config file: option 'ipv6_first' must be a boolean");
conf.ipv6_first = value->u.boolean;
- }
+ } else if (strcmp(name, "tcp_tproxy") == 0) {
+ check_json_value_type(value, json_boolean,
+ "invalid config file: option 'tcp_tproxy' must be a boolean");
+ conf.tcp_tproxy = value->u.boolean;
+ }
}
}
} else {
--- a/src/jconf.h
+++ b/src/jconf.h
@@ -105,6 +105,7 @@ typedef struct {
int mtu;
int mptcp;
int ipv6_first;
+ int tcp_tproxy;
} jconf_t;
jconf_t *read_jconf(const char *file);
--- a/src/redir.c
+++ b/src/redir.c
@@ -71,6 +71,14 @@
#define IP6T_SO_ORIGINAL_DST 80
#endif
+#ifndef IP_TRANSPARENT
+#define IP_TRANSPARENT 19
+#endif
+
+#ifndef IPV6_TRANSPARENT
+#define IPV6_TRANSPARENT 75
+#endif
+
#include "includeobfs.h" // I don't want to modify makefile
#include "jconf.h"
@@ -101,18 +109,28 @@ static struct cork_dllist inactive_profi
static listen_ctx_t *current_profile;
static struct cork_dllist all_connections;
+static int tcp_tproxy = 0; /* use tproxy instead of redirect (for tcp) */
+
int
getdestaddr(int fd, struct sockaddr_storage *destaddr)
{
socklen_t socklen = sizeof(*destaddr);
int error = 0;
- error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen);
- if (error) { // Didn't find a proper way to detect IP version.
- error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen);
- if (error) {
- return -1;
- }
+ if (tcp_tproxy) {
+ error = getsockname(fd, (void *)destaddr, &socklen);
+ } else {
+ error = getsockopt(fd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, destaddr, &socklen);
+ if (error) { // Didn't find a proper way to detect IP version.
+ error = getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, destaddr, &socklen);
+ if (error) {
+ return -1;
+ }
+ }
+ }
+
+ if (error) {
+ return -1;
}
return 0;
}
@@ -164,6 +182,23 @@ create_and_bind(const char *addr, const
if (err == 0) {
LOGI("tcp port reuse enabled");
}
+
+ if (tcp_tproxy) {
+ int level = 0, optname = 0;
+ if (rp->ai_family == AF_INET) {
+ level = IPPROTO_IP;
+ optname = IP_TRANSPARENT;
+ } else {
+ level = IPPROTO_IPV6;
+ optname = IPV6_TRANSPARENT;
+ }
+
+ if (setsockopt(listen_sock, level, optname, &opt, sizeof(opt)) != 0) {
+ ERROR("setsockopt IP_TRANSPARENT");
+ exit(EXIT_FAILURE);
+ }
+ LOGI("tcp tproxy mode enabled");
+ }
s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen);
if (s == 0) {
@@ -1094,7 +1129,7 @@ main(int argc, char **argv)
USE_TTY();
- while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUvA6"
+ while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUTvA6"
"O:o:G:g:",
long_options, &option_index)) != -1) {
switch (c) {
@@ -1169,6 +1204,9 @@ main(int argc, char **argv)
case 'U':
mode = UDP_ONLY;
break;
+ case 'T':
+ tcp_tproxy = 1;
+ break;
case 'v':
verbose = 1;
break;
@@ -1255,6 +1293,9 @@ main(int argc, char **argv)
if (mode == TCP_ONLY) {
mode = conf->mode;
}
+ if (tcp_tproxy == 0) {
+ tcp_tproxy = conf->tcp_tproxy;
+ }
if (mtu == 0) {
mtu = conf->mtu;
}
--- a/src/utils.c
+++ b/src/utils.c
@@ -342,6 +342,10 @@ usage()
#endif
printf(
" [-U] Enable UDP relay and disable TCP relay.\n");
+#ifdef MODULE_REDIR
+ printf(
+ " [-T] Use tproxy instead of redirect (for tcp).\n");
+#endif
#ifdef MODULE_REMOTE
printf(
" [-6] Resovle hostname to IPv6 address first.\n");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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