diff --git a/ss-rust.sh b/ss-rust.sh index e156cc3..e0133f6 100644 --- a/ss-rust.sh +++ b/ss-rust.sh @@ -23,6 +23,11 @@ METHOD_2022="" PORT_RAW="" KEY_RAW="" METHOD_RAW="" +PORT_OBFS="" +KEY_OBFS="" +METHOD_OBFS="" +OBFS_BACKEND_PORT="" +OBFS_HOST="" NODE_MODE="" # ============ 基础检测 ============ @@ -45,9 +50,9 @@ get_pkg_manager() { install_deps() { info "安装依赖..." case $PKG in - apt) apt update -qq &>/dev/null; apt install -y -qq curl openssl xz-utils tar chrony python3 &>/dev/null ;; - yum) yum install -y -q curl openssl xz tar chrony python3 &>/dev/null ;; - apk) apk add --quiet curl openssl xz tar chrony python3 &>/dev/null ;; + apt) apt update -qq &>/dev/null; apt install -y -qq curl openssl xz-utils tar chrony python3 ca-certificates &>/dev/null ;; + yum) yum install -y -q curl openssl xz tar chrony python3 ca-certificates &>/dev/null ;; + apk) apk add --quiet curl openssl xz tar chrony python3 ca-certificates &>/dev/null ;; esac } @@ -179,6 +184,41 @@ install_ssrust() { /usr/local/bin/ssserver --version && info "shadowsocks-rust 安装完成" || error "安装验证失败" } +# ============ 安装 simple-obfs ============ +install_simple_obfs() { + command -v obfs-server &>/dev/null && return 0 + info "安装 simple-obfs (HTTP 伪装插件)..." + + case $PKG in + apt) + apt update -qq &>/dev/null + apt install -y -qq --no-install-recommends git build-essential autoconf automake libtool pkg-config libssl-dev libev-dev libc-ares-dev libpcre2-dev asciidoc xmlto &>/dev/null \ + || error "安装 simple-obfs 编译依赖失败" + ;; + yum) + yum install -y -q git gcc gcc-c++ make autoconf automake libtool pkgconfig openssl-devel libev-devel c-ares-devel pcre-devel asciidoc xmlto &>/dev/null \ + || error "安装 simple-obfs 编译依赖失败" + ;; + apk) + apk add --quiet git build-base autoconf automake libtool pkgconf openssl-dev libev-dev c-ares-dev pcre2-dev asciidoc xmlto &>/dev/null \ + || error "安装 simple-obfs 编译依赖失败" + ;; + esac + + rm -rf /tmp/simple-obfs-src + git clone --depth=1 https://github.com/shadowsocks/simple-obfs.git /tmp/simple-obfs-src &>/dev/null \ + || error "下载 simple-obfs 失败" + cd /tmp/simple-obfs-src + git submodule update --init --recursive &>/dev/null || true + ./autogen.sh &>/tmp/simple-obfs-autogen.log || error "simple-obfs autogen 失败: /tmp/simple-obfs-autogen.log" + ./configure --disable-documentation &>/tmp/simple-obfs-configure.log || error "simple-obfs configure 失败: /tmp/simple-obfs-configure.log" + make -j"$(nproc 2>/dev/null || echo 1)" &>/tmp/simple-obfs-make.log || error "simple-obfs 编译失败: /tmp/simple-obfs-make.log" + make install &>/tmp/simple-obfs-install.log || error "simple-obfs 安装失败: /tmp/simple-obfs-install.log" + ldconfig 2>/dev/null || true + command -v obfs-server &>/dev/null || error "simple-obfs 安装验证失败" + info "simple-obfs 安装完成" +} + # ============ 节点选择 + 端口密码 + 写配置 ============ select_and_configure() { SERVER_IP=$(get_ip) @@ -187,6 +227,7 @@ select_and_configure() { # 清空 PORT_2022="" ; KEY_2022="" ; METHOD_2022="" PORT_RAW="" ; KEY_RAW="" ; METHOD_RAW="" + PORT_OBFS="" ; KEY_OBFS="" ; METHOD_OBFS="" ; OBFS_BACKEND_PORT="" ; OBFS_HOST="" echo "" echo -e "${CYAN}════════════════════════════════════════${NC}" @@ -196,8 +237,9 @@ select_and_configure() { echo -e " ${GREEN}1.${NC} SS2022-128 (2022-blake3-aes-128-gcm) — 新协议,推荐" echo -e " ${GREEN}2.${NC} SS-AES-128 (aes-128-gcm) — 传统协议,兼容性好" echo -e " ${GREEN}3.${NC} 双节点全装 (SS2022 + SS128)" + echo -e " ${GREEN}4.${NC} SS2022-128 + HTTP obfs (simple-obfs 伪装)" echo "" - read -rp "请选择 [1-3] (默认3): " node_choice + read -rp "请选择 [1-4] (默认3): " node_choice node_choice=${node_choice:-3} if [[ "$node_choice" == "1" || "$node_choice" == "3" ]]; then @@ -224,6 +266,24 @@ select_and_configure() { METHOD_RAW="aes-128-gcm" fi + if [[ "$node_choice" == "4" ]]; then + local dp3=$((RANDOM % 10000 + 20000)) + local dk3=$(openssl rand -base64 16) + local bp=$((RANDOM % 10000 + 40000)) + echo "" + echo -e " ${GREEN}SS2022-128 + HTTP obfs 配置:${NC}" + read -rp " 对外端口 [回车=${dp3}]: " PORT_OBFS + PORT_OBFS=${PORT_OBFS:-$dp3} + read -rp " 后端本地端口 [回车=${bp}]: " OBFS_BACKEND_PORT + OBFS_BACKEND_PORT=${OBFS_BACKEND_PORT:-$bp} + read -rp " 密码 [回车=${dk3}]: " KEY_OBFS + KEY_OBFS=${KEY_OBFS:-$dk3} + read -rp " 伪装 Host [回车=www.microsoft.com]: " OBFS_HOST + OBFS_HOST=${OBFS_HOST:-www.microsoft.com} + METHOD_OBFS="2022-blake3-aes-128-gcm" + install_simple_obfs + fi + # 写 JSON 配置 python3 -c " import json @@ -246,11 +306,32 @@ if '${PORT_RAW}': 'timeout': 300, 'fast_open': True }) +if '${PORT_OBFS}': + servers.append({ + 'server': '127.0.0.1', + 'server_port': int('${OBFS_BACKEND_PORT}'), + 'method': '${METHOD_OBFS}', + 'password': '${KEY_OBFS}', + 'timeout': 300, + 'fast_open': True + }) with open('/etc/shadowsocks-rust/config.json', 'w') as f: json.dump({'servers': servers}, f, indent=4) print('OK') " || error "生成配置失败" + if [[ -n "$PORT_OBFS" ]]; then + cat > /etc/shadowsocks-rust/obfs.env </dev/null || true + rm -f /etc/systemd/system/ss-rust-obfs.service + systemctl daemon-reload + return 0 + fi + + # shellcheck disable=SC1091 + source /etc/shadowsocks-rust/obfs.env + install_simple_obfs + + cat > /etc/systemd/system/ss-rust-obfs.service << EOF +[Unit] +Description=Shadowsocks simple-obfs HTTP Frontend +After=network.target ss-rust.service +Wants=ss-rust.service + +[Service] +Type=simple +ExecStart=/usr/local/bin/obfs-server -s 0.0.0.0 -p ${PORT_OBFS} -r 127.0.0.1:${OBFS_BACKEND_PORT} --obfs http --http-method GET +Restart=on-failure +RestartSec=5 +LimitNOFILE=65535 + +[Install] +WantedBy=multi-user.target +EOF + + systemctl daemon-reload + systemctl enable --now ss-rust-obfs + sleep 1 + + if systemctl is-active --quiet ss-rust-obfs; then + info "simple-obfs 服务启动成功: 0.0.0.0:${PORT_OBFS} -> 127.0.0.1:${OBFS_BACKEND_PORT}" + else + journalctl -u ss-rust-obfs -n 10 --no-pager + error "simple-obfs 服务启动失败" + fi } # ============ 读取现有配置 ============ @@ -290,6 +414,7 @@ load_config() { SERVER_IP=$(get_ip) PORT_2022="" ; KEY_2022="" ; METHOD_2022="" PORT_RAW="" ; KEY_RAW="" ; METHOD_RAW="" + PORT_OBFS="" ; KEY_OBFS="" ; METHOD_OBFS="" ; OBFS_BACKEND_PORT="" ; OBFS_HOST="" eval $(python3 -c " import json @@ -306,6 +431,13 @@ for s in c['servers']: print(f'KEY_RAW={s[\"password\"]}') print(f'METHOD_RAW={m}') " 2>/dev/null) + if [[ -f /etc/shadowsocks-rust/obfs.env ]]; then + # shellcheck disable=SC1091 + source /etc/shadowsocks-rust/obfs.env + if [[ -n "$OBFS_BACKEND_PORT" && "$PORT_2022" == "$OBFS_BACKEND_PORT" ]]; then + PORT_2022="" ; KEY_2022="" ; METHOD_2022="" + fi + fi return 0 } @@ -335,6 +467,18 @@ gen_subscribe() { info_txt="${info_txt}【SS-AES-128】传统协议\n 地址: ${SERVER_IP}\n 端口: ${PORT_RAW}\n 加密: ${METHOD_RAW}\n 密码: ${KEY_RAW}\n\n" fi + if [[ -n "$PORT_OBFS" ]]; then + local plugin_raw="obfs-local;obfs=http;obfs-host=${OBFS_HOST}" + local plugin_enc + plugin_enc=$(PLUGIN_RAW="$plugin_raw" python3 -c 'import os, urllib.parse; print(urllib.parse.quote(os.environ["PLUGIN_RAW"], safe=""))') + local uri="ss://$(echo -n "${METHOD_OBFS}:${KEY_OBFS}" | base64 -w0)@${SERVER_IP}:${PORT_OBFS}/?plugin=${plugin_enc}#SS2022-OBFS-HTTP" + URI_OBFS="$uri" + uris="${uris}${uri}\n" + surge="${surge}SS2022-OBFS-HTTP = ss, ${SERVER_IP}, ${PORT_OBFS}, encrypt-method=${METHOD_OBFS}, password=${KEY_OBFS}, obfs=http, obfs-host=${OBFS_HOST}\n" + clash="${clash} - name: SS2022-OBFS-HTTP\n type: ss\n server: ${SERVER_IP}\n port: ${PORT_OBFS}\n cipher: ${METHOD_OBFS}\n password: \"${KEY_OBFS}\"\n udp: false\n plugin: obfs\n plugin-opts:\n mode: http\n host: ${OBFS_HOST}\n\n" + info_txt="${info_txt}【SS2022 + HTTP obfs】simple-obfs 伪装\n 地址: ${SERVER_IP}\n 端口: ${PORT_OBFS}\n 加密: ${METHOD_OBFS}\n 密码: ${KEY_OBFS}\n 插件: obfs/http\n Host: ${OBFS_HOST}\n 后端: 127.0.0.1:${OBFS_BACKEND_PORT}\n\n" + fi + echo -e "$uris" | base64 -w0 > "$sub_dir/subscribe.txt" echo -e "# Surge SS | $(date '+%Y-%m-%d %H:%M:%S') | ${SERVER_IP}\n[Proxy]\n${surge}" > "$sub_dir/surge.conf" @@ -369,16 +513,29 @@ show_result() { echo "" fi + if [[ -n "$PORT_OBFS" ]]; then + echo -e "${GREEN}【SS2022 + HTTP obfs】simple-obfs 伪装${NC}" + echo -e " 地址: ${SERVER_IP}" + echo -e " 端口: ${YELLOW}${PORT_OBFS}${NC}" + echo -e " 加密: ${METHOD_OBFS}" + echo -e " 密码: ${YELLOW}${KEY_OBFS}${NC}" + echo -e " 插件: obfs / http" + echo -e " Host: ${OBFS_HOST}" + echo "" + fi + echo -e "${CYAN}────────────────────────────────────────${NC}" echo -e "${GREEN}【Surge 格式】${NC}" [[ -n "$PORT_2022" ]] && echo " SS2022-128 = ss, ${SERVER_IP}, ${PORT_2022}, encrypt-method=${METHOD_2022}, password=${KEY_2022}" [[ -n "$PORT_RAW" ]] && echo " SS-AES-128 = ss, ${SERVER_IP}, ${PORT_RAW}, encrypt-method=${METHOD_RAW}, password=${KEY_RAW}" + [[ -n "$PORT_OBFS" ]] && echo " SS2022-OBFS-HTTP = ss, ${SERVER_IP}, ${PORT_OBFS}, encrypt-method=${METHOD_OBFS}, password=${KEY_OBFS}, obfs=http, obfs-host=${OBFS_HOST}" echo "" echo -e "${CYAN}────────────────────────────────────────${NC}" echo -e "${GREEN}【SS 链接】${NC}" [[ -n "${URI_2022:-}" ]] && echo " ${URI_2022}" [[ -n "${URI_RAW:-}" ]] && echo " ${URI_RAW}" + [[ -n "${URI_OBFS:-}" ]] && echo " ${URI_OBFS}" echo "" echo -e "${CYAN}────────────────────────────────────────${NC}" @@ -422,6 +579,7 @@ if 0 <= idx < len(c['servers']): json.dump(c, f, indent=4) " systemctl restart ss-rust + setup_obfs_service gen_subscribe info "端口已改为 ${new_port}" } @@ -438,7 +596,25 @@ for s in c['servers']: with open('/etc/shadowsocks-rust/config.json','w') as f: json.dump(c, f, indent=4) " + if [[ -f /etc/shadowsocks-rust/obfs.env ]]; then + local new_obfs_key + new_obfs_key=$(openssl rand -base64 16) + sed -i "s|^KEY_OBFS=.*|KEY_OBFS=${new_obfs_key}|" /etc/shadowsocks-rust/obfs.env + # shellcheck disable=SC1091 + source /etc/shadowsocks-rust/obfs.env + python3 -c " +import json +with open('/etc/shadowsocks-rust/config.json') as f: + c = json.load(f) +for s in c.get('servers', []): + if str(s.get('server_port')) == '${OBFS_BACKEND_PORT}': + s['password'] = '${KEY_OBFS}' +with open('/etc/shadowsocks-rust/config.json','w') as f: + json.dump(c, f, indent=4) +" + fi systemctl restart ss-rust + setup_obfs_service gen_subscribe info "密钥已重置" show_result @@ -590,9 +766,9 @@ SYSCTL # ============ 卸载 ============ uninstall() { warn "卸载 shadowsocks-rust..." - systemctl stop ss-rust 2>/dev/null - systemctl disable ss-rust 2>/dev/null - rm -f /etc/systemd/system/ss-rust.service + systemctl stop ss-rust ss-rust-obfs 2>/dev/null + systemctl disable ss-rust ss-rust-obfs 2>/dev/null + rm -f /etc/systemd/system/ss-rust.service /etc/systemd/system/ss-rust-obfs.service rm -f /usr/local/bin/ssserver /usr/local/bin/sslocal /usr/local/bin/ssurl rm -rf /etc/shadowsocks-rust systemctl daemon-reload @@ -644,8 +820,8 @@ show_menu() { 4) reset_keys ;; 5) systemctl start ss-rust && info "已启动" ;; 6) systemctl stop ss-rust && info "已停止" ;; - 7) systemctl restart ss-rust && info "已重启" ;; - 8) journalctl -u ss-rust --no-pager -n 30 ;; + 7) systemctl restart ss-rust; setup_obfs_service; info "已重启" ;; + 8) journalctl -u ss-rust -u ss-rust-obfs --no-pager -n 50 ;; 9) uninstall ;; 10) setup_bbr ;; 11) get_pkg_manager; install_deps; sync_time ;; @@ -661,10 +837,10 @@ main() { install) do_install ;; uninstall|remove) uninstall ;; show|config|info) show_config ;; - restart) systemctl restart ss-rust && info "已重启" ;; + restart) systemctl restart ss-rust; setup_obfs_service; info "已重启" ;; start) systemctl start ss-rust && info "已启动" ;; stop) systemctl stop ss-rust && info "已停止" ;; - log|logs) journalctl -u ss-rust --no-pager -n 30 ;; + log|logs) journalctl -u ss-rust -u ss-rust-obfs --no-pager -n 50 ;; reset) reset_keys ;; bbr) setup_bbr ;; sync|time) get_pkg_manager; install_deps; sync_time ;;