diff --git a/xray-manager.sh b/xray-manager.sh index a1befc8..12d545a 100755 --- a/xray-manager.sh +++ b/xray-manager.sh @@ -26,7 +26,7 @@ _log() { [ "$level" != "debug" ] && logger -t xray-manager -p "daemon.$syslog_level" "$message" if [ "$to_console" = "1" ]; then - printf "%s\n" "$message" + printf "%s\n" "$message" >&2 fi } @@ -55,6 +55,12 @@ _collect_list() { eval "$__out_varname=\"\$__accum\"" } +_curl_proxy_args() { + [ -n "$CURL_PROXY" ] || return + printf -- "--proxy %s " "$CURL_PROXY" + [ -n "$CURL_PROXY_USER" ] && printf -- "--proxy-user %s:%s " "$CURL_PROXY_USER" "$CURL_PROXY_PASS" +} + _fetch_url() { local id="$1" url="$2" local url_hash=$(echo "$url" | md5sum | cut -c1-8) @@ -64,10 +70,10 @@ _fetch_url() { local body_tmp="$CACHE_DIR/dl_${id}_${url_hash}.raw" local etag=$(cat "$etag_file" 2>/dev/null) - curl -sSfL --connect-timeout 15 --retry 3 --retry-connrefused --retry-delay 5 ${etag:+-H "If-None-Match: \"$etag\""} -D "$header_tmp" "$url" > "$body_tmp" + curl -4 -sSfL --connect-timeout 15 --retry-connrefused --retry-delay 5 $(_curl_proxy_args) ${etag:+-H "If-None-Match: \"$etag\""} -D "$header_tmp" "$url" > "$body_tmp" local curl_status=$? - if grep -q "304" "$header_tmp" 2>/dev/null; then + if grep -qE '^HTTP/[0-9.]+ +304' "$header_tmp" 2>/dev/null; then _log "$id: 304 not modified" "info" rm -f "$body_tmp" "$header_tmp" [ -f "$cache_raw" ] && { cat "$cache_raw"; return 0; } @@ -99,22 +105,25 @@ _init_vars() { config_load xray-manager MAIN_SECTION="main" - _cfg_get_default TABLE "table_name" - _cfg_get_default TPROXY_PORT "tproxy_port" - _cfg_get_default TPROXY_MARK "tproxy_mark" - _cfg_get_default CLIENT_MARK "client_mark" - _cfg_get_default RT_TABLE "rt_table" - _cfg_get_default TIMEOUT "timeout" - _cfg_get_default EXCLUDE_MARK "exclude_mark" "0x1" - _cfg_get_default PRIO_EXC "prio_exc" "-200" - _cfg_get_default PRIO_PROXY "prio_proxy" "-150" - _cfg_get_default PRIO_OUTPUT "prio_output" "-100" - _cfg_get_default IPNET_DIR "ipnet_dir" '/tmp/.xray-manager/ipnet' - _cfg_get_default DNSMASQ_DIR "dnsmasq_dir" '/tmp/.xray-manager/dnsmasq.d' - _cfg_get_default CACHE_DIR "cache_dir" '/tmp/.xray-manager/cache' - _cfg_get_default ACTIVE_LIST "active_list" '/tmp/.xray-manager/active_files' - _cfg_get_default DOMSTAGE_DIR "domstage_dir" "$CACHE_DIR/domstage" - _cfg_get_default CTX_DIR "ctx_dir" "$CACHE_DIR/ctx" + _cfg_get_default TABLE "table_name" + _cfg_get_default TPROXY_PORT "tproxy_port" + _cfg_get_default TPROXY_MARK "tproxy_mark" + _cfg_get_default CLIENT_MARK "client_mark" + _cfg_get_default RT_TABLE "rt_table" + _cfg_get_default TIMEOUT "timeout" + _cfg_get_default EXCLUDE_MARK "exclude_mark" "0x1" + _cfg_get_default PRIO_EXC "prio_exc" "-200" + _cfg_get_default PRIO_PROXY "prio_proxy" "-150" + _cfg_get_default PRIO_OUTPUT "prio_output" "-100" + _cfg_get_default IPNET_DIR "ipnet_dir" '/tmp/.xray-manager/ipnet' + _cfg_get_default DNSMASQ_DIR "dnsmasq_dir" '/tmp/.xray-manager/dnsmasq.d' + _cfg_get_default CACHE_DIR "cache_dir" '/tmp/.xray-manager/cache' + _cfg_get_default ACTIVE_LIST "active_list" '/tmp/.xray-manager/active_files' + _cfg_get_default DOMSTAGE_DIR "domstage_dir" "$CACHE_DIR/domstage" + _cfg_get_default CTX_DIR "ctx_dir" "$CACHE_DIR/ctx" + _cfg_get_default CURL_PROXY "curl_proxy" + _cfg_get_default CURL_PROXY_USER "curl_proxy_user" + _cfg_get_default CURL_PROXY_PASS "curl_proxy_pass" local required_vars="TABLE TPROXY_PORT TPROXY_MARK CLIENT_MARK RT_TABLE TIMEOUT" for var in $required_vars; do @@ -125,6 +134,11 @@ _init_vars() { fi done + if [ "$((EXCLUDE_MARK))" -eq "$((TPROXY_MARK))" ] 2>/dev/null; then + _log "config: exclude_mark ($EXCLUDE_MARK) must differ from tproxy_mark ($TPROXY_MARK)" "crit" + return 1 + fi + _log "config: loaded table=$TABLE, port=$TPROXY_PORT, mark=$TPROXY_MARK" "debug" mkdir -p "$IPNET_DIR" "$DNSMASQ_DIR" "$CACHE_DIR" "$DOMSTAGE_DIR" "$CTX_DIR" "${ACTIVE_LIST%/*}" @@ -150,6 +164,36 @@ _get_src_names() { fi } +_get_dst_names() { + local section="$1" name + config_get name "$section" name + if [ -n "$name" ]; then + _sanitize_name name "$name" + case " $existing_dst_names " in + *" $name "*) + _log "config: duplicate xray-dst name '$name' - names must be unique within xray-dst!" "crit" + has_errors=1 + ;; + esac + existing_dst_names="${existing_dst_names}${existing_dst_names:+ }$name" + fi +} + +_get_out_names() { + local section="$1" name + config_get name "$section" name + if [ -n "$name" ]; then + _sanitize_name name "$name" + case " $existing_out_names " in + *" $name "*) + _log "config: duplicate xray-out name '$name' - names must be unique within xray-out!" "crit" + has_errors=1 + ;; + esac + existing_out_names="${existing_out_names}${existing_out_names:+ }$name" + fi +} + _validate_list_section() { local section="$1" name type config_get name "$section" name @@ -206,7 +250,11 @@ _validate_config() { local allowed_opts="name exclude parent ip domain url_ip url_domain" local has_errors=0 local existing_src_names="" + local existing_dst_names="" + local existing_out_names="" config_foreach _get_src_names "xray-src" + config_foreach _get_dst_names "xray-dst" + config_foreach _get_out_names "xray-out" config_foreach _validate_list_section "xray-src" config_foreach _validate_list_section "xray-dst" @@ -350,14 +398,24 @@ _process_item() { local tmp_all="$CACHE_DIR/dl_$id" : > "$tmp_all" local download_ok=0 + local part_files="" pids="" n=0 part pid for url in $value; do + n=$((n + 1)) + part="$tmp_all.part${n}.$$" + part_files="${part_files}${part_files:+ }$part" _log "$id: downloading $url" "debug" - if _fetch_url "$id" "$url" >> "$tmp_all"; then - download_ok=1 - fi + _fetch_url "$id" "$url" > "$part" & + pids="${pids}${pids:+ }$!" done + for pid in $pids; do + wait "$pid" && download_ok=1 + done + + cat $part_files > "$tmp_all" 2>/dev/null + rm -f $part_files + if [ "$download_ok" = "1" ] && [ -s "$tmp_all" ]; then if [ "$type" = "uip" ]; then sed -e 's/\r//g' -e '/^#/d' -e '/^[[:space:]]*$/d' "$tmp_all" | awk '{ print ($1 ~ /\// ? $1 : $1"/32") }' | sort -u > "$fullpath.tmp" @@ -795,4 +853,4 @@ case "$1" in reload) export SKIP_URL=1; _run "incr" ;; update) export SKIP_URL=0; _run "incr" ;; *) echo "Usage: $0 {start|stop|restart|reload|update}"; exit 1 ;; -esac \ No newline at end of file +esac