426 lines
10 KiB
Bash
426 lines
10 KiB
Bash
#!/bin/sh
|
|
|
|
WARP_CONF="/etc/sing-box-warp/warp.conf"
|
|
OUTPUT_CONFIG="/opt/sing-box-warp/config.json"
|
|
|
|
urldecode() {
|
|
echo "$1" | sed 's/%3[dD]/=/g; s/%2[bB]/+/g; s/%2[fF]/\//g; s/%2[cC]/,/g'
|
|
}
|
|
|
|
trim() {
|
|
echo "$1" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
|
|
}
|
|
|
|
normalize_cidr() {
|
|
local addr
|
|
local suffix
|
|
addr=$(trim "$1")
|
|
suffix="$2"
|
|
|
|
if [ -z "$addr" ]; then
|
|
echo ""
|
|
return
|
|
fi
|
|
|
|
case "$addr" in
|
|
*/*) echo "$addr" ;;
|
|
*) echo "${addr}/${suffix}" ;;
|
|
esac
|
|
}
|
|
|
|
# Extract parameter from URL
|
|
get_param() {
|
|
local url="$1"
|
|
local param="$2"
|
|
echo "$url" | sed -n "s/.*[?&]${param}=\([^&#]*\).*/\1/p"
|
|
}
|
|
|
|
parse_from_wg_url() {
|
|
WG_URL=$(grep "^wg://" "$WARP_CONF" | head -1)
|
|
|
|
if [ -z "$WG_URL" ]; then
|
|
echo "Error: No wg:// URL found in $WARP_CONF"
|
|
exit 1
|
|
fi
|
|
|
|
SERVER=$(echo "$WG_URL" | sed 's|wg://\([^:]*\):.*|\1|')
|
|
PORT=$(echo "$WG_URL" | sed 's|wg://[^:]*:\([0-9]*\)?.*|\1|')
|
|
|
|
PRIVATE_KEY=$(urldecode "$(get_param "$WG_URL" "private_key")")
|
|
PUBLIC_KEY=$(urldecode "$(get_param "$WG_URL" "peer_public_key")")
|
|
MTU=$(get_param "$WG_URL" "mtu")
|
|
LOCAL_ADDRESS=$(urldecode "$(get_param "$WG_URL" "local_address")")
|
|
|
|
Jc=$(get_param "$WG_URL" "junk_packet_count")
|
|
Jmin=$(get_param "$WG_URL" "junk_packet_min_size")
|
|
Jmax=$(get_param "$WG_URL" "junk_packet_max_size")
|
|
H1=$(get_param "$WG_URL" "init_packet_magic_header")
|
|
H2=$(get_param "$WG_URL" "response_packet_magic_header")
|
|
H3=$(get_param "$WG_URL" "underload_packet_magic_header")
|
|
H4=$(get_param "$WG_URL" "transport_packet_magic_header")
|
|
|
|
IPV4=$(echo "$LOCAL_ADDRESS" | tr ',-' '\n' | sed -n '1p')
|
|
IPV6=$(echo "$LOCAL_ADDRESS" | tr ',-' '\n' | sed -n '2p')
|
|
|
|
IPV4=$(normalize_cidr "$IPV4" 32)
|
|
IPV6=$(normalize_cidr "$IPV6" 128)
|
|
|
|
if [ -z "$IPV4" ]; then
|
|
echo "Error: local_address (IPv4) is empty"
|
|
exit 1
|
|
fi
|
|
|
|
ADDRESS_JSON=$(printf '"%s"' "$IPV4")
|
|
|
|
MTU=${MTU:-1280}
|
|
Jc=${Jc:-4}
|
|
Jmin=${Jmin:-40}
|
|
Jmax=${Jmax:-70}
|
|
H1=${H1:-1}
|
|
H2=${H2:-2}
|
|
H3=${H3:-3}
|
|
H4=${H4:-4}
|
|
|
|
ALLOWED_IPS="0.0.0.0/0"
|
|
TAG="wireguard-out"
|
|
LOG_LEVEL="debug"
|
|
}
|
|
|
|
parse_from_ini() {
|
|
local section=""
|
|
local key=""
|
|
local value=""
|
|
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
line=$(trim "$line")
|
|
[ -z "$line" ] && continue
|
|
|
|
case "$line" in
|
|
\#*|\;*) continue ;;
|
|
esac
|
|
|
|
case "$line" in
|
|
"[Interface]") section="Interface"; continue ;;
|
|
"[Peer]") section="Peer"; continue ;;
|
|
esac
|
|
|
|
key=$(trim "$(echo "$line" | cut -d'=' -f1)")
|
|
value=$(trim "$(echo "$line" | cut -d'=' -f2-)")
|
|
[ -z "$key" ] && continue
|
|
|
|
if [ "$section" = "Interface" ]; then
|
|
case "$key" in
|
|
PrivateKey) PRIVATE_KEY="$value" ;;
|
|
Address)
|
|
IPV4=$(trim "$(echo "$value" | cut -d',' -f1)")
|
|
IPV6=$(trim "$(echo "$value" | cut -d',' -f2)")
|
|
;;
|
|
MTU) MTU="$value" ;;
|
|
S1) S1="$value" ;;
|
|
S2) S2="$value" ;;
|
|
S3) S3="$value" ;;
|
|
Jc) Jc="$value" ;;
|
|
Jmin) Jmin="$value" ;;
|
|
Jmax) Jmax="$value" ;;
|
|
H1) H1="$value" ;;
|
|
H2) H2="$value" ;;
|
|
H3) H3="$value" ;;
|
|
H4) H4="$value" ;;
|
|
I1) I1="$value" ;;
|
|
I2) I2="$value" ;;
|
|
esac
|
|
elif [ "$section" = "Peer" ]; then
|
|
case "$key" in
|
|
PublicKey) PUBLIC_KEY="$value" ;;
|
|
AllowedIPs)
|
|
if echo "$value" | grep -q "0.0.0.0/0"; then
|
|
ALLOWED_IPS="0.0.0.0/0"
|
|
else
|
|
ALLOWED_IPS=$(trim "$(echo "$value" | cut -d',' -f1)")
|
|
fi
|
|
;;
|
|
Endpoint)
|
|
SERVER=$(echo "$value" | cut -d':' -f1)
|
|
PORT=$(echo "$value" | cut -d':' -f2)
|
|
;;
|
|
esac
|
|
fi
|
|
done < "$WARP_CONF"
|
|
|
|
IPV4=$(normalize_cidr "$IPV4" 32)
|
|
IPV6=$(normalize_cidr "$IPV6" 128)
|
|
|
|
if [ -z "$IPV4" ]; then
|
|
echo "Error: Address (IPv4) is empty"
|
|
exit 1
|
|
fi
|
|
|
|
ADDRESS_JSON=$(printf '"%s"' "$IPV4")
|
|
|
|
MTU=${MTU:-1280}
|
|
S1=${S1:-0}
|
|
S2=${S2:-0}
|
|
S3=${S3:-0}
|
|
Jc=${Jc:-4}
|
|
Jmin=${Jmin:-40}
|
|
Jmax=${Jmax:-70}
|
|
H1=${H1:-1}
|
|
H2=${H2:-2}
|
|
H3=${H3:-3}
|
|
H4=${H4:-4}
|
|
ALLOWED_IPS=${ALLOWED_IPS:-0.0.0.0/0}
|
|
|
|
if [ -z "$SERVER" ] || [ -z "$PORT" ]; then
|
|
echo "Error: Endpoint is empty"
|
|
exit 1
|
|
fi
|
|
|
|
TAG="wireguard-out"
|
|
LOG_LEVEL="error"
|
|
}
|
|
|
|
write_config() {
|
|
if [ -n "$I1" ] || [ -n "$I2" ]; then
|
|
H4_COMMA=","
|
|
else
|
|
H4_COMMA=""
|
|
fi
|
|
|
|
if [ -n "$I1" ] && [ -n "$I2" ]; then
|
|
I1_LINE=$(printf ' "i1": "%s",\n' "$I1")
|
|
I2_LINE=$(printf ' "i2": "%s"\n' "$I2")
|
|
elif [ -n "$I1" ]; then
|
|
I1_LINE=$(printf ' "i1": "%s"\n' "$I1")
|
|
I2_LINE=""
|
|
elif [ -n "$I2" ]; then
|
|
I1_LINE=""
|
|
I2_LINE=$(printf ' "i2": "%s"\n' "$I2")
|
|
else
|
|
I1_LINE=""
|
|
I2_LINE=""
|
|
fi
|
|
|
|
cat > "$OUTPUT_CONFIG" <<EOF
|
|
{
|
|
"log": {
|
|
"level": "$LOG_LEVEL"
|
|
},
|
|
"dns": {
|
|
"servers": [
|
|
{
|
|
"tag": "default",
|
|
"type": "udp",
|
|
"server": "76.76.2.0",
|
|
"detour": "direct"
|
|
},
|
|
{
|
|
"tag": "dns-proxy",
|
|
"type": "tls",
|
|
"server": "8.8.8.8",
|
|
"detour": "wireguard-out"
|
|
},
|
|
{
|
|
"tag": "local",
|
|
"type": "udp",
|
|
"server": "127.0.0.1",
|
|
"detour": "direct"
|
|
}
|
|
]
|
|
},
|
|
"endpoints": [
|
|
{
|
|
"type": "wireguard",
|
|
"tag": "$TAG",
|
|
"mtu": $MTU,
|
|
"address": $ADDRESS_JSON,
|
|
"private_key": "$PRIVATE_KEY",
|
|
"listen_port": 10000,
|
|
"peers": [
|
|
{
|
|
"address": "$SERVER",
|
|
"port": $PORT,
|
|
"public_key": "$PUBLIC_KEY",
|
|
"allowed_ips": "$ALLOWED_IPS"
|
|
}
|
|
],
|
|
"udp_timeout": "5m0s",
|
|
"amnezia": {
|
|
"jc": $Jc,
|
|
"jmin": $Jmin,
|
|
"jmax": $Jmax,
|
|
"s1": ${S1:-0},
|
|
"s2": ${S2:-0},
|
|
"h1": $H1,
|
|
"h2": $H2,
|
|
"h3": $H3,
|
|
"h4": $H4$H4_COMMA
|
|
$I1_LINE
|
|
$I2_LINE
|
|
}
|
|
}
|
|
],
|
|
"inbounds": [
|
|
{
|
|
"type": "mixed",
|
|
"tag": "mixed-in",
|
|
"listen_port": 2080
|
|
},
|
|
{
|
|
"type": "tun",
|
|
"tag": "tun-in",
|
|
"interface_name": "sing0",
|
|
"address": "172.19.0.1/30",
|
|
"mtu": 1500,
|
|
"auto_route": true,
|
|
"stack": "system"
|
|
}
|
|
],
|
|
"outbounds": [
|
|
{
|
|
"type": "direct",
|
|
"tag": "direct"
|
|
}
|
|
],
|
|
"route": {
|
|
"rule_set": [
|
|
{
|
|
"tag": "antifilter_allyouneed",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/antifilter_allyouneed.srs"
|
|
},
|
|
{
|
|
"tag": "antizapret",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/antizapret.srs"
|
|
},
|
|
{
|
|
"tag": "github_ip_you-oops-dev",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/github_ip_you-oops-dev.srs"
|
|
},
|
|
{
|
|
"tag": "github_karingx",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/github_karingx.srs"
|
|
},
|
|
{
|
|
"tag": "cloudfront_ip_MetaCubeX",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/cloudfront_ip_MetaCubeX.srs"
|
|
},
|
|
{
|
|
"tag": "telegram_MetaCubeX",
|
|
"type": "local",
|
|
"format": "binary",
|
|
"path": "/opt/sing-box-warp/rules/telegram_MetaCubeX.srs"
|
|
}
|
|
],
|
|
"rules": [
|
|
{
|
|
"ip_cidr": [
|
|
"51.38.122.1",
|
|
"5.28.195.0/24",
|
|
"185.76.151.0/24",
|
|
"91.105.0.0/16",
|
|
"91.108.4.0/22",
|
|
"91.108.8.0/21",
|
|
"91.108.12.0/22",
|
|
"91.108.16.0/21",
|
|
"91.108.20.0/22",
|
|
"91.108.56.0/22",
|
|
"95.161.64.0/20",
|
|
"149.154.0.0/16",
|
|
"185.76.151.0/24",
|
|
"185.76.151.0/24",
|
|
"5.28.195.0/24",
|
|
"142.252.0.0/16",
|
|
"173.239.0.0/16",
|
|
"173.194.0.0/16",
|
|
"194.221.61.0/24",
|
|
"45.142.38.0/24",
|
|
"209.85.0.0/16",
|
|
"216.239.0.0/16"
|
|
],
|
|
"outbound": "$TAG"
|
|
},
|
|
{
|
|
"inbound": "mixed-in",
|
|
"outbound": "$TAG"
|
|
},
|
|
{
|
|
"rule_set": [
|
|
"antifilter_allyouneed",
|
|
"antizapret",
|
|
"github_ip_you-oops-dev",
|
|
"github_karingx",
|
|
"cloudfront_ip_MetaCubeX",
|
|
"telegram_MetaCubeX"
|
|
],
|
|
"outbound": "$TAG"
|
|
},
|
|
{
|
|
"rule_set": [
|
|
"antifilter_allyouneed",
|
|
"antizapret",
|
|
"github_ip_you-oops-dev",
|
|
"github_karingx",
|
|
"cloudfront_ip_MetaCubeX",
|
|
"telegram_MetaCubeX"
|
|
],
|
|
"outbound": "$TAG"
|
|
},
|
|
{
|
|
"domain_suffix": [
|
|
"myip.wtf",
|
|
"ip.sb",
|
|
"ipify.org",
|
|
"myip.la",
|
|
"ipleak.net",
|
|
"1e100.net",
|
|
"browserleaks.com",
|
|
"2ip.io",
|
|
"2ipcore.com",
|
|
"ipecho.net"
|
|
],
|
|
"outbound": "$TAG"
|
|
}
|
|
],
|
|
"final": "direct",
|
|
"auto_detect_interface": true,
|
|
"default_domain_resolver": "default"
|
|
}
|
|
}
|
|
EOF
|
|
}
|
|
|
|
parse_warp_conf() {
|
|
local first_line
|
|
first_line=$(head -n 1 "$WARP_CONF" | tr -d '\r')
|
|
first_line=$(trim "$first_line")
|
|
|
|
if echo "$first_line" | grep -q "^wg://"; then
|
|
parse_from_wg_url
|
|
elif echo "$first_line" | grep -q "^\[Interface\]"; then
|
|
parse_from_ini
|
|
else
|
|
echo "Error: Unsupported warp.conf format (expected wg:// or [Interface])"
|
|
exit 1
|
|
fi
|
|
|
|
write_config
|
|
}
|
|
|
|
# Main
|
|
if [ ! -f "$WARP_CONF" ]; then
|
|
echo "Error: $WARP_CONF not found!"
|
|
exit 1
|
|
fi
|
|
|
|
parse_warp_conf
|
|
echo "Config generated successfully at $OUTPUT_CONFIG"
|