diff options
author | Yousong Zhou <yszhou4tech@gmail.com> | 2017-06-24 08:56:18 +0800 |
---|---|---|
committer | Yousong Zhou <yszhou4tech@gmail.com> | 2017-07-02 10:01:53 +0800 |
commit | b61af9703e64dff5e3a1deff1ce1886c1470dbe7 (patch) | |
tree | 5703718b7279b7a9b4c04a20e757a65340aa33bf /net/shadowsocks-libev/files | |
parent | 1aca235d44a32af9ffc515ca74153e3954abf9ca (diff) |
shadowsocks-libev: rewrite
- Selecting only a single or subset of all components of shadowsocks-libev is
now possible (this is the main motivation behind the rewrite)
- Configuring multiple instances of the same component is now also possible
- Same option names as with the json config
- Unified configuration generation method for each component
- Add support for ss-local, ss-tunnel, ss-server
- Most data validation is now done with validate_data
- USE_PROCD=1
- Update ss-rules with the one from shadowsocks/luci-app-shadowsocks
- Add README.md
- Set myself as the maintainer
Addresses #4435
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
Diffstat (limited to 'net/shadowsocks-libev/files')
-rw-r--r-- | net/shadowsocks-libev/files/firewall.include | 6 | ||||
-rw-r--r-- | net/shadowsocks-libev/files/firewall.ss-rules | 2 | ||||
-rw-r--r-- | net/shadowsocks-libev/files/shadowsocks-libev.config | 71 | ||||
-rw-r--r-- | net/shadowsocks-libev/files/shadowsocks-libev.init | 436 | ||||
-rw-r--r-- | net/shadowsocks-libev/files/ss-rules | 323 | ||||
-rwxr-xr-x | net/shadowsocks-libev/files/ss-rules.defaults | 10 |
6 files changed, 550 insertions, 298 deletions
diff --git a/net/shadowsocks-libev/files/firewall.include b/net/shadowsocks-libev/files/firewall.include deleted file mode 100644 index 3a00e8025..000000000 --- a/net/shadowsocks-libev/files/firewall.include +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -if pidof ss-redir>/dev/null; then - /etc/init.d/shadowsocks-libev rules - logger -t ShadowSocks-libev "Reloading ShadowSocks-libev due to restart of firewall" -fi diff --git a/net/shadowsocks-libev/files/firewall.ss-rules b/net/shadowsocks-libev/files/firewall.ss-rules new file mode 100644 index 000000000..3a1d32cdc --- /dev/null +++ b/net/shadowsocks-libev/files/firewall.ss-rules @@ -0,0 +1,2 @@ +#!/bin/sh +/etc/init.d/shadowsocks-libev reload diff --git a/net/shadowsocks-libev/files/shadowsocks-libev.config b/net/shadowsocks-libev/files/shadowsocks-libev.config index 95aec7b2e..9b3fe0852 100644 --- a/net/shadowsocks-libev/files/shadowsocks-libev.config +++ b/net/shadowsocks-libev/files/shadowsocks-libev.config @@ -1,15 +1,60 @@ - -config shadowsocks-libev - option enable '1' - option server '127.0.0.1' - option server_port '8388' +config ss_local + option disabled 1 + option server 'sss0' + option local_address '0.0.0.0' option local_port '1080' - option password 'barfoo!' + 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' - option encrypt_method 'rc4-md5' - option ignore_list '/dev/null' - option udp_mode '0' - option tunnel_enable '1' - option tunnel_port '5300' - option tunnel_forward '8.8.4.4:53' - option lan_ac_mode '0' + +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 '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' + option bind_address '192.168.7.72' diff --git a/net/shadowsocks-libev/files/shadowsocks-libev.init b/net/shadowsocks-libev/files/shadowsocks-libev.init index 9a64038a7..68ec93b03 100644 --- a/net/shadowsocks-libev/files/shadowsocks-libev.init +++ b/net/shadowsocks-libev/files/shadowsocks-libev.init @@ -1,156 +1,316 @@ #!/bin/sh /etc/rc.common +# +# Copyright (C) 2017 Yousong Zhou <yszhou4tech@gmail.com> +# +# This is free software, licensed under the GNU General Public License v3. +# See /LICENSE for more information. +# -START=90 -STOP=15 - -SERVICE_USE_PID=1 -SERVICE_WRITE_PID=1 -SERVICE_DAEMONIZE=1 -EXTRA_COMMANDS="rules" -CONFIG_FILE=/var/etc/shadowsocks-libev.json - -get_config() { - config_get_bool enable $1 enable - config_get server $1 server - config_get server_port $1 server_port - config_get local_port $1 local_port - config_get timeout $1 timeout - config_get password $1 password - config_get encrypt_method $1 encrypt_method - config_get ignore_list $1 ignore_list - config_get udp_mode $1 udp_mode - config_get udp_server $1 udp_server - config_get udp_server_port $1 udp_server_port - config_get udp_local_port $1 udp_local_port - config_get udp_timeout $1 udp_timeout - config_get udp_password $1 udp_password - config_get udp_encrypt_method $1 udp_encrypt_method - config_get_bool tunnel_enable $1 tunnel_enable - config_get tunnel_port $1 tunnel_port - config_get tunnel_forward $1 tunnel_forward - config_get lan_ac_mode $1 lan_ac_mode - config_get lan_ac_ip $1 lan_ac_ip - config_get wan_bp_ip $1 wan_bp_ip - config_get wan_fw_ip $1 wan_fw_ip - config_get ipt_ext $1 ipt_ext - : ${timeout:=60} - : ${udp_timeout:=60} - : ${tunnel_port:=5300} - : ${tunnel_forward:=8.8.4.4:53} -} - -start_rules() { - local ac_args - - if [ -n "$lan_ac_ip" ]; then - case $lan_ac_mode in - 1) ac_args="w$lan_ac_ip" - ;; - 2) ac_args="b$lan_ac_ip" - ;; - esac +USE_PROCD=1 +START=99 + +ss_confdir=/var/etc/shadowsocks-libev +ss_bindir=/usr/bin +q='"' + +ss_mkjson() { + echo "{" >"$confjson" + if ss_mkjson_ "$@" >>$confjson; then + sed -i -e '/^\s*$/d' -e '2,$s/^/\t/' -e '$s/,$//' "$confjson" + echo "}" >>"$confjson" + else + rm -f "$confjson" + return 1 fi - /usr/bin/ss-rules \ - -s "$server" \ - -l "$local_port" \ - -S "$udp_server" \ - -L "$udp_local_port" \ - -i "$ignore_list" \ - -a "$ac_args" \ - -b "$wan_bp_ip" \ - -w "$wan_fw_ip" \ - -e "$ipt_ext" \ - -o $udp - return $? -} - -start_redir() { - cat <<-EOF >$CONFIG_FILE - { - "server": "$server", - "server_port": $server_port, - "local_address": "0.0.0.0", - "local_port": $local_port, - "password": "$password", - "timeout": $timeout, - "method": "$encrypt_method" - } -EOF - if [ "$udp_mode" = 2 ]; then - /usr/bin/ss-redir \ - -c $CONFIG_FILE \ - -f /var/run/ss-redir_t.pid - cat <<-EOF >$CONFIG_FILE - { - "server": "$udp_server", - "server_port": $udp_server_port, - "local_address": "0.0.0.0", - "local_port": $udp_local_port, - "password": "$udp_password", - "timeout": $udp_timeout, - "method": "$udp_encrypt_method" - } -EOF +} + +ss_mkjson_() { + local func + + for func in "$@"; do + if ! "$func"; then + return 1 + fi + done +} + +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 + cat <<-EOF + ${server:+${q}server${q}: ${q}$server${q},} + "server_port": $server_port, + ${method:+${q}method${q}: ${q}$method${q},} + ${key:+${q}key${q}: ${q}$key${q},} + ${password:+${q}password${q}: ${q}$password${q},} + EOF +} + +ss_mkjson_common_conf() { + [ "$fast_open" = 0 ] && fast_open=false || fast_open=true + [ "$reuse_port" = 0 ] && reuse_port=false || reuse_port=true + cat <<-EOF + "use_syslog": true, + "fast_open": $fast_open, + "reuse_port": $reuse_port, + ${local_address:+${q}local_address${q}: ${q}$local_address${q},} + ${local_port:+${q}local_port${q}: $local_port,} + ${mode:+${q}mode${q}: ${q}$mode${q},} + ${mtu:+${q}mtu${q}: $mtu,} + ${timeout:+${q}timeout${q}: $timeout,} + ${user:+${q}user${q}: ${q}$user${q},} + EOF +} + +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 + cat <<-EOF + ${tunnel_address:+${q}tunnel_address${q}: ${q}$tunnel_address${q},} + EOF +} + +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" + [ "$disabled" = 0 ] || return + + if ss_mkjson \ + ss_mkjson_common_conf \ + ss_mkjson_${cfgtype}_conf \ + ; then + procd_open_instance "$cfgtype.$cfg" + procd_set_param command "$bin" -c "$confjson" + [ "$verbose" = 0 ] || procd_append_param command -v + [ -z "$bind_address" ] || procd_append_param command -b "$bind_address" + [ -z "$manager_address" ] || procd_append_param command --manager-address "$manager_address" + procd_set_param file "$confjson" + procd_set_param respawn + procd_close_instance + ss_rules_cb "$cfg" fi - /usr/bin/ss-redir \ - -c $CONFIG_FILE \ - -f /var/run/ss-redir.pid \ - $udp - return $? } -start_tunnel() { - : ${udp:="-u"} - /usr/bin/ss-tunnel \ - -c $CONFIG_FILE \ - -l $tunnel_port \ - -L $tunnel_forward \ - -f /var/run/ss-tunnel.pid \ - $udp - return $? +ss_rules_cb() { + local cfgserver + local server + + [ "$cfgtype" != ss_server ] || return + config_get cfgserver "$cfg" server + config_get server "$cfgserver" server + + ss_rules_servers="$ss_rules_servers $server" + if [ "$cfgtype" = ss_redir ]; then + 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" + eval "ss_rules_redir_server_udp_$cfg=$server" + fi + fi } -rules() { - config_load shadowsocks-libev - config_foreach get_config shadowsocks-libev - [ "$enable" = 1 ] || exit 0 - mkdir -p /var/run /var/etc - - : ${server:?} - : ${server_port:?} - : ${local_port:?} - : ${password:?} - : ${encrypt_method:?} - case $udp_mode in - 1) udp="-u" - ;; - 2) - udp="-U" - : ${udp_server:?} - : ${udp_server_port:?} - : ${udp_local_port:?} - : ${udp_password:?} - : ${udp_encrypt_method:?} - ;; +ss_rules() { + local cfg="ss_rules" + local bin="$ss_bindir/ss-rules" + local cfgtype + local args local_port_tcp local_port_udp server_udp + local i a_args d_args + + [ -x "$bin" ] || 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" + [ "$disabled" = 0 ] || return 1 + + eval local_port_tcp="\$ss_rules_redir_tcp_$redir_tcp" + eval local_port_udp="\$ss_rules_redir_udp_$redir_udp" + eval server_udp="\$ss_rules_redir_server_udp_$redir_udp" + [ -z "$local_port_udp" ] || args="$args -U" + case "$local_default" in + forward) args="$args -O" ;; + checkdst) args="$args -o" ;; + esac + case "$src_default" in + bypass) d_args=RETURN ;; + forward) d_args=SS_SPEC_WAN_FW ;; + checkdst) d_args=SS_SPEC_WAN_AC ;; esac + ss_rules_servers="$(echo "$ss_rules_servers" | tr ' ' '\n' | sort -u)" + for i in $src_ips_bypass; do a_args="b,$i $a_args"; done + for i in $src_ips_forward; do a_args="g,$i $a_args"; done + for i in $src_ips_checkdst; do a_args="n,$i $a_args"; done + + "$bin" \ + -s "$ss_rules_servers" \ + -l "$local_port_tcp" \ + -S "$server_udp" \ + -L "$local_port_udp" \ + -B "$dst_ips_bypass_file" \ + -W "$dst_ips_forward_file" \ + -b "$dst_ips_bypass" \ + -w "$dst_ips_forward" \ + -e "$ipt_args" \ + -a "$a_args" \ + -d "$d_args" \ + $args \ + || "$bin" -f +} + +start_service() { + local cfgtype="$1" + + 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() { + local bin="$ss_bindir/ss-rules" + + [ -x "$bin" ] && "$bin" -f + rm -rf "$ss_confdir" +} - start_rules +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 } -boot() { - until iptables-save -t nat | grep -q "^:zone_lan_prerouting"; do - sleep 1 +ss_validate_mklocal() { + local tuple opts + + shift 2 + for tuple in "$@"; do + opts="${tuple%%:*} $opts" done - start + [ -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"' + + "${func:-ss_validate}" "$cfgtype" "$cfg" "$@" \ + 'disabled:bool:false' \ + 'server:host' \ + 'server_port:port' \ + 'password:string' \ + 'key:string' \ + "method:or($stream_methods, $aead_methods)" +} + +validate_common_client_options_() { + validate_common_options_ "$@" \ + 'server:uci("shadowsocks-libev", "@server")' \ + 'local_address:host: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:false' \ + 'verbose:bool:false' \ + 'fast_open:bool:false' \ + 'reuse_port:bool:false' \ + 'mode:or("tcp_only", "udp_only", "tcp_and_udp")' \ + '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}" +} + +validate_ss_redir_section() { + validate_common_client_options_ ss_redir "$1" "${2}" +} + +validate_ss_rules_section() { + "${2:-ss_validate}" ss_rules "$1" \ + 'disabled:bool:false' \ + 'redir_tcp:uci("shadowsocks-libev", "@ss_redir")' \ + 'redir_udp:uci("shadowsocks-libev", "@ss_redir")' \ + 'src_ips_bypass:list(ipaddr)' \ + 'src_ips_forward:list(ipaddr)' \ + 'src_ips_checkdst:list(ipaddr)' \ + 'dst_ips_bypass_file:file' \ + 'dst_ips_bypass:list(ipaddr)' \ + 'dst_ips_forward_file:file' \ + 'dst_ips_forward:list(ipaddr)' \ + 'src_default:or("bypass", "forward", "checkdst")' \ + 'local_default:or("bypass", "forward", "checkdst")' \ + 'ipt_args:string' } -start() { - rules && start_redir - [ "$tunnel_enable" = 1 ] && start_tunnel +validate_ss_server_section() { + validate_common_server_options_ ss_server "$1" \ + validate_common_options_ \ + "${2}" \ + 'bind_address:ipaddr' \ + 'manager_address:host' } -stop() { - /usr/bin/ss-rules -f - killall -q -9 ss-redir - killall -q -9 ss-tunnel +validate_ss_tunnel_section() { + validate_common_client_options_ ss_tunnel "$1" \ + "${2}" \ + 'tunnel_address:regex(".+\:[0-9]+")' } diff --git a/net/shadowsocks-libev/files/ss-rules b/net/shadowsocks-libev/files/ss-rules index 8ce1000cb..8bd7264af 100644 --- a/net/shadowsocks-libev/files/ss-rules +++ b/net/shadowsocks-libev/files/ss-rules @@ -1,4 +1,10 @@ #!/bin/sh +# +# Copyright (C) 2014-2017 Jian Chang <aa65535@live.com> +# +# This is free software, licensed under the GNU General Public License v3. +# See /LICENSE for more information. +# usage() { cat <<-EOF @@ -6,20 +12,28 @@ usage() { Valid options are: - -s <server_host> hostname or ip of shadowsocks remote server + -s <server_ips> ip address of shadowsocks remote server -l <local_port> port number of shadowsocks local server - -i <ip_list_file> a file content is bypassed ip list - -a <lan_ips> lan ip of access control, need a prefix to - define access control mode + -S <server_ips> ip address of shadowsocks remote UDP server + -L <local_port> port number of shadowsocks local UDP server + -B <ip_list_file> a file whose content is bypassed ip list -b <wan_ips> wan ip of will be bypassed + -W <ip_list_file> a file whose content is forwarded ip list -w <wan_ips> wan ip of will be forwarded - -e <extra_options> extra options for iptables + -I <interface> proxy only for the given interface + -d <target> the default target of lan access control + -a <lan_hosts> lan ip of access control, need a prefix to + define proxy type + -e <extra_args> extra arguments for iptables -o apply the rules to the OUTPUT chain + -O apply the global rules to the OUTPUT chain -u enable udprelay mode, TPROXY is required -U enable udprelay mode, using different IP and ports for TCP and UDP -f flush the rules + -h show this help message and exit EOF + exit $1 } loger() { @@ -27,135 +41,192 @@ loger() { logger -st ss-rules[$$] -p$1 $2 } -ipt_n="iptables -t nat" -ipt_m="iptables -t mangle" - -flush_r() { - local IPT - - IPT=$(iptables-save -t nat) - eval $(echo "$IPT" | grep "_SS_SPEC_RULE_" | \ - sed -e 's/^-A/$ipt_n -D/' -e 's/$/;/') - - for chain in $(echo "$IPT" | awk '/^:SS_SPEC/{print $1}'); do - $ipt_n -F ${chain:1} 2>/dev/null && $ipt_n -X ${chain:1} - done - - IPT=$(iptables-save -t mangle) - eval $(echo "$IPT" | grep "_SS_SPEC_RULE_" | \ - sed -e 's/^-A/$ipt_m -D/' -e 's/$/;/') - - for chain in $(echo "$IPT" | awk '/^:SS_SPEC/{print $1}'); do - $ipt_m -F ${chain:1} 2>/dev/null && $ipt_m -X ${chain:1} +flush_rules() { + iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c + if command -v ip >/dev/null 2>&1; then + ip rule del fwmark 1 lookup 100 2>/dev/null + ip route del local default dev lo table 100 2>/dev/null + fi + for setname in $(ipset -n list | grep "ss_spec"); do + ipset destroy $setname 2>/dev/null done - - ip rule del fwmark 0x01/0x01 table 100 2>/dev/null - ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null - ipset -X ss_spec_lan_ac 2>/dev/null - ipset -X ss_spec_wan_ac 2>/dev/null + FWI=$(uci get firewall.shadowsocks.path 2>/dev/null) + [ -n "$FWI" ] && echo '# firewall include file' >$FWI return 0 } -ipset_r() { - ipset -! -R <<-EOF || return 1 - create ss_spec_wan_ac hash:net - $(echo -e "$IPLIST" | sed -e "s/^/add ss_spec_wan_ac /") - $(for ip in $WAN_FW_IP; do echo "add ss_spec_wan_ac $ip nomatch"; done) +ipset_init() { + ipset -! restore <<-EOF || return 1 + create ss_spec_src_ac hash:ip hashsize 64 + create ss_spec_src_bp hash:ip hashsize 64 + create ss_spec_src_fw hash:ip hashsize 64 + create ss_spec_dst_sp hash:net hashsize 64 + create ss_spec_dst_bp hash:net hashsize 64 + create ss_spec_dst_fw hash:net hashsize 64 + $(gen_lan_host_ipset_entry) + $(gen_special_purpose_ip | sed -e "s/^/add ss_spec_dst_sp /") + $(sed -e "s/^/add ss_spec_dst_bp /" ${WAN_BP_LIST:=/dev/null} 2>/dev/null) + $(for ip in $WAN_BP_IP; do echo "add ss_spec_dst_bp $ip"; done) + $(sed -e "s/^/add ss_spec_dst_fw /" ${WAN_FW_LIST:=/dev/null} 2>/dev/null) + $(for ip in $WAN_FW_IP; do echo "add ss_spec_dst_fw $ip"; done) EOF - $ipt_n -N SS_SPEC_WAN_AC && \ - $ipt_n -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN && \ - $ipt_n -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW - return $? + return 0 } -fw_rule() { - $ipt_n -N SS_SPEC_WAN_FW && \ - $ipt_n -A SS_SPEC_WAN_FW -p tcp \ - -j REDIRECT --to-ports $local_port 2>/dev/null || { - loger 3 "Can't redirect, please check the iptables." - exit 1 - } +ipt_nat() { + include_ac_rules nat + ipt="iptables -t nat" + $ipt -A SS_SPEC_WAN_FW -p tcp \ + -j REDIRECT --to-ports $local_port || return 1 + if [ -n "$OUTPUT" ]; then + $ipt -N SS_SPEC_WAN_DG + $ipt -A SS_SPEC_WAN_DG -m set --match-set ss_spec_dst_sp dst -j RETURN + $ipt -A SS_SPEC_WAN_DG -p tcp $EXT_ARGS -j $OUTPUT + $ipt -I OUTPUT 1 -p tcp -j SS_SPEC_WAN_DG + fi return $? } -ac_rule() { - local TAG ROUTECHAIN - - if [ -n "$LAN_AC_IP" ]; then - if [ "${LAN_AC_IP:0:1}" = "w" ]; then - TAG="nomatch" - else - if [ "${LAN_AC_IP:0:1}" != "b" ]; then - loger 3 "Bad argument \`-a $LAN_AC_IP\`." - return 2 - fi - fi +ipt_mangle() { + [ -n "$TPROXY" ] || return 0 + if !(lsmod | grep -q TPROXY && command -v ip >/dev/null); then + loger 4 "TPROXY or ip not found." + return 0 fi + ip rule add fwmark 1 lookup 100 + ip route add local default dev lo table 100 + include_ac_rules mangle + iptables -t mangle -A SS_SPEC_WAN_FW -p udp \ + -j TPROXY --on-port $LOCAL_PORT --tproxy-mark 0x01/0x01 + return $? +} - ROUTECHAIN=PREROUTING - if iptables-save -t nat | grep -q "^:zone_lan_prerouting"; then - ROUTECHAIN=zone_lan_prerouting - fi +export_ipt_rules() { + [ -n "$FWI" ] || return 0 + cat <<-CAT >>$FWI + iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c + iptables-restore -n <<-EOF + $(iptables-save | grep -E "SS_SPEC|^\*|^COMMIT" |\ + sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/") + EOF +CAT + return $? +} + +gen_lan_host_ipset_entry() { + for host in $LAN_HOSTS; do + case "${host:0:1}" in + n|N) + echo add ss_spec_src_ac ${host:2} + ;; + b|B) + echo add ss_spec_src_bp ${host:2} + ;; + g|G) + echo add ss_spec_src_fw ${host:2} + ;; + esac + done +} - ipset -! -R <<-EOF || return 1 - create ss_spec_lan_ac hash:net - $(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip $TAG"; done) +gen_special_purpose_ip() { + cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}" + 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 + 255.255.255.255 + $server + $SERVER EOF - $ipt_n -A $ROUTECHAIN -p tcp $EXT_ARGS \ - -m set ! --match-set ss_spec_lan_ac src \ - -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_WAN_AC +} - if [ "$OUTPUT" = 1 ]; then - $ipt_n -A OUTPUT -p tcp $EXT_ARGS \ - -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_WAN_AC - fi - return $? +include_ac_rules() { + local protocol=$([ "$1" = "mangle" ] && echo udp || echo tcp) + iptables-restore -n <<-EOF + *$1 + :SS_SPEC_LAN_DG - [0:0] + :SS_SPEC_LAN_AC - [0:0] + :SS_SPEC_WAN_AC - [0:0] + :SS_SPEC_WAN_FW - [0:0] + -A SS_SPEC_LAN_DG -m set --match-set ss_spec_dst_sp dst -j RETURN + -A SS_SPEC_LAN_DG -p $protocol $EXT_ARGS -j SS_SPEC_LAN_AC + -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_bp src -j RETURN + -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_fw src -j SS_SPEC_WAN_FW + -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_ac src -j SS_SPEC_WAN_AC + -A SS_SPEC_LAN_AC -j ${LAN_TARGET:=SS_SPEC_WAN_AC} + -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_fw dst -j SS_SPEC_WAN_FW + -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_bp dst -j RETURN + -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW + $(gen_prerouting_rules $protocol) + COMMIT +EOF } -tp_rule() { - [ -n "$TPROXY" ] || return 0 - ip rule add fwmark 0x01/0x01 table 100 - ip route add local 0.0.0.0/0 dev lo table 100 - $ipt_m -N SS_SPEC_TPROXY - $ipt_m -A SS_SPEC_TPROXY -p udp -m set ! --match-set ss_spec_wan_ac dst \ - -j TPROXY --on-port $LOCAL_PORT --tproxy-mark 0x01/0x01 - $ipt_m -A PREROUTING -p udp $EXT_ARGS \ - -m set ! --match-set ss_spec_lan_ac src \ - -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_TPROXY - return $? +gen_prerouting_rules() { + [ -z "$IFNAMES" ] && echo -I PREROUTING 1 -p $1 -j SS_SPEC_LAN_DG + for ifname in $IFNAMES; do + echo -I PREROUTING 1 -i $ifname -p $1 -j SS_SPEC_LAN_DG + done } -while getopts ":s:l:S:L:i:e:a:b:w:ouUf" arg; do - case $arg in +while getopts ":s:l:S:L:B:b:W:w:I:d:a:e:oOuUfh" arg; do + case "$arg" in s) - server=$OPTARG + server=$(for ip in $OPTARG; do echo $ip; done) ;; l) local_port=$OPTARG ;; S) - SERVER=$OPTARG + SERVER=$(for ip in $OPTARG; do echo $ip; done) ;; L) LOCAL_PORT=$OPTARG ;; - i) - IGNORE=$OPTARG - ;; - e) - EXT_ARGS=$OPTARG - ;; - a) - LAN_AC_IP=$OPTARG + B) + WAN_BP_LIST=$OPTARG ;; b) - WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done) + WAN_BP_IP=$OPTARG + ;; + W) + WAN_FW_LIST=$OPTARG ;; w) WAN_FW_IP=$OPTARG ;; + I) + IFNAMES=$OPTARG + ;; + d) + LAN_TARGET=$OPTARG + ;; + a) + LAN_HOSTS=$OPTARG + ;; + e) + EXT_ARGS=$OPTARG + ;; o) - OUTPUT=1 + OUTPUT=SS_SPEC_WAN_AC + ;; + O) + OUTPUT=SS_SPEC_WAN_FW ;; u) TPROXY=1 @@ -164,56 +235,26 @@ while getopts ":s:l:S:L:i:e:a:b:w:ouUf" arg; do TPROXY=2 ;; f) - flush_r + flush_rules exit 0 ;; + h) + usage 0 + ;; esac done -if [ -z "$server" -o -z "$local_port" ]; then - usage - exit 2 -fi +[ -z "$server" -o -z "$local_port" ] && usage 2 if [ "$TPROXY" = 1 ]; then - SERVER=$server + unset SERVER LOCAL_PORT=$local_port +elif [ "$TPROXY" = 2 ]; then + : ${SERVER:?"You must assign an ip for the udp relay server."} + : ${LOCAL_PORT:?"You must assign a port for the udp relay server."} fi -if [ "$TPROXY" = 2 ]; then - if [ -z "$SERVER" -o -z "$LOCAL_PORT" ]; then - loger 3 "Please use -S and -L specifies IP and port for UDP." - fi -fi - -if [ -f "$IGNORE" ]; then - IGNORE_IP=$(cat $IGNORE 2>/dev/null) -fi - -IPLIST=$(cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}" - $server - $SERVER - 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.88.99.0/24 - 192.168.0.0/16 - 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 - 255.255.255.255 - $WAN_BP_IP - $IGNORE_IP -EOF -) - -flush_r && fw_rule && ipset_r && ac_rule && tp_rule - -exit $? +flush_rules && ipset_init && ipt_nat && ipt_mangle && export_ipt_rules +RET=$? +[ "$RET" = 0 ] || loger 3 "Start failed!" +exit $RET diff --git a/net/shadowsocks-libev/files/ss-rules.defaults b/net/shadowsocks-libev/files/ss-rules.defaults new file mode 100755 index 000000000..c89e2d0b8 --- /dev/null +++ b/net/shadowsocks-libev/files/ss-rules.defaults @@ -0,0 +1,10 @@ +#!/bin/sh + +s=firewall.ss_rules +uci get "$s" >/dev/null && exit 0 +uci batch <<-EOF + set $s=include + set $s.path=/etc/firewall.ss-rules + set $s.reload=1 + commit firewall +EOF |