大量更新

This commit is contained in:
zeaslity
2025-07-10 16:49:54 +08:00
parent ee93d8dc8c
commit d6025287a0
49 changed files with 4620 additions and 164 deletions

View File

@@ -0,0 +1,22 @@
version: '3.8'
services:
crawl4ai:
image: unclecode/crawl4ai:basic
ports:
- "1235:11235"
environment:
- CRAWL4AI_API_TOKEN=${CRAWL4AI_API_TOKEN:-} # Optional API security
- MAX_CONCURRENT_TASKS=${CRAWL4AI_API_TOKEN:-}
# LLM Provider Keys
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- GEMINI_API_KEY=${GEMINI_API_KEY:-}
volumes:
- /dev/shm:/dev/shm
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 1G

View File

@@ -0,0 +1,9 @@
# API Security (optional)
CRAWL4AI_API_TOKEN=EP53z52yx1r8k87G7y34AMojqpCHU4eMxO1MEGOBwa5mlDYe
# LLM Provider Keys
OPENAI_API_KEY=sk-proj-lCRIbBe3ex7VJP5GzAklT3BlbkFJbOcB4cXRQKk7pNZjBCHM
GEMINI_API_KEY=AIzaSyBv2JN5aY_OKDI5e1aVEf6uDQli65X9NZM
# Other Configuration
MAX_CONCURRENT_TASKS=5

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
这篇文章揭露了豆粕市场崩盘背后的资本博弈和行业乱象,核心内容包括:
1. **资本操控**:豆粕价格暴跌并非单纯市场供需所致,而是压榨巨头和饲料企业为争夺定价权进行的资本博弈,散户成为牺牲品。
1. **需求疲软假象**:所谓的“需求疲软”实则是饲料企业为保利润调整配方,减少豆粕用量,而养殖户因成本上升和猪周期下行遭受重创。
1. **开工率谎言**:压榨企业通过“停机检修”人为控制供应,制造紧张假象以操纵价格,同时过度依赖进口大豆威胁国内农业生态和产业安全。
2. **库存猫腻**:“缺豆不缺粕”的异常现象暗示压榨企业和贸易商囤积居奇,通过信息不对称和低买高卖剥削散户。
1. **未来预测争议**卓创资讯对4月豆粕价格走势的预测被质疑可能受利益集团影响提醒投资者保持独立判断警惕市场陷阱。

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# 1GB 1048576 5G 1048576 8G 8388608 # 1GB 1048576 5G 1048576 8G 8388608
sudo modprobe brd rd_nr=1 rd_size=8388608 max_part=1 sudo modprobe brd rd_nr=1 rd_size=1048576 max_part=1
sudo mkfs.ext4 /dev/ram0 sudo mkfs.ext4 /dev/ram0

View File

@@ -5,7 +5,7 @@ services:
postgresql: postgresql:
image: docker.io/bitnami/postgresql:15 image: docker.io/bitnami/postgresql:15
volumes: volumes:
- '/data/gitea/postgresql_data/:/bitnami/postgresql' - '/var/lib/docker/wdd/gitea/postgresql_data/:/bitnami/postgresql'
environment: environment:
- POSTGRESQL_DATABASE=gitea_db - POSTGRESQL_DATABASE=gitea_db
- POSTGRESQL_USERNAME=bn_gitea - POSTGRESQL_USERNAME=bn_gitea
@@ -14,7 +14,7 @@ services:
gitea: gitea:
image: docker.io/bitnami/gitea:1.19.3-debian-11-r0 image: docker.io/bitnami/gitea:1.19.3-debian-11-r0
volumes: volumes:
- '/data/gitea/gitea_data:/bitnami/gitea' - '/var/lib/docker/wdd/gitea/gitea_data:/bitnami/gitea'
environment: environment:
- GITEA_DATABASE_HOST=postgresql - GITEA_DATABASE_HOST=postgresql
- GITEA_DATABASE_NAME=gitea_db - GITEA_DATABASE_NAME=gitea_db
@@ -26,7 +26,7 @@ services:
- GITEA_HTTP_PORT=3000 - GITEA_HTTP_PORT=3000
- GITEA_SSH_LISTEN_PORT=22222 - GITEA_SSH_LISTEN_PORT=22222
- GITEA_APP_NAME=Gitea-闲下来就喝杯茶吧 - GITEA_APP_NAME=Gitea-闲下来就喝杯茶吧
- GITEA_DOMAIN=192.168.35.70 - GITEA_DOMAIN=192.168.35.80
- GITEA_PROTOCOL=http - GITEA_PROTOCOL=http
- GITEA_RUN_MODE=prod - GITEA_RUN_MODE=prod
ports: ports:

View File

@@ -410,11 +410,14 @@ x-shared-env: &shared-api-worker-env
MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true} MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true}
MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai} MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true} FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
PLUGIN_PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
services: services:
# API service # API service
api: api:
image: langgenius/dify-api:0.15.3 image: langgenius/dify-api:1.1.3
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -426,15 +429,19 @@ services:
SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
dns:
- 1.1.1.1
- 8.8.8.8
volumes: volumes:
# Mount the storage directory to the container, for storing user files. # Mount the storage directory to the container, for storing user files.
- /mnt/ramdisk/dify-api/storage:/app/api/storage - /mnt/ramdisk/dify-api/storage:/app/api/storage
- /etc/resolv.conf:/etc/resolv.conf
network_mode: "host" network_mode: "host"
# worker service # worker service
# The Celery worker for processing the queue. # The Celery worker for processing the queue.
worker: worker:
image: langgenius/dify-api:0.15.3 image: langgenius/dify-api:1.1.3
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -449,14 +456,16 @@ services:
volumes: volumes:
# Mount the storage directory to the container, for storing user files. # Mount the storage directory to the container, for storing user files.
- /mnt/ramdisk/dify-api/storage:/app/api/storage - /mnt/ramdisk/dify-api/storage:/app/api/storage
- /etc/resolv.conf:/etc/resolv.conf
dns:
- 1.1.1.1
- 8.8.8.8
network_mode: "host" network_mode: "host"
# Frontend web application. # Frontend web application.
web: web:
image: langgenius/dify-web:0.15.3 image: langgenius/dify-web:1.1.3
restart: always restart: always
ports:
- '3000:3000'
environment: environment:
CONSOLE_API_URL: ${CONSOLE_API_URL:-} CONSOLE_API_URL: ${CONSOLE_API_URL:-}
APP_API_URL: ${APP_API_URL:-} APP_API_URL: ${APP_API_URL:-}
@@ -468,10 +477,12 @@ services:
MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai} MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-} TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-} INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-}
ports:
- 3000:3000
# The DifySandbox # The DifySandbox
sandbox: sandbox:
image: langgenius/dify-sandbox:0.2.10 image: langgenius/dify-sandbox:0.2.11
restart: always restart: always
environment: environment:
# The DifySandbox configurations # The DifySandbox configurations
@@ -486,14 +497,19 @@ services:
SANDBOX_PORT: ${SANDBOX_PORT:-8194} SANDBOX_PORT: ${SANDBOX_PORT:-8194}
volumes: volumes:
- /mnt/ramdisk/sandbox/dependencies:/dependencies - /mnt/ramdisk/sandbox/dependencies:/dependencies
- /etc/resolv.conf:/etc/resolv.conf
dns:
- 1.1.1.1
- 8.8.8.8
healthcheck: healthcheck:
test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ] test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ]
networks: network_mode: "host"
- default
# plugin daemon # plugin daemon
plugin_daemon: plugin_daemon:
image: langgenius/dify-plugin-daemon:0.0.2-local image: langgenius/dify-plugin-daemon:0.0.6-local
restart: always restart: always
environment: environment:
# Use the shared environment variables. # Use the shared environment variables.
@@ -506,13 +522,19 @@ services:
DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
DIFY_INNER_API_KEY: ${INNER_API_KEY_FOR_PLUGIN:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} DIFY_INNER_API_KEY: ${INNER_API_KEY_FOR_PLUGIN:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_REMOTE_INSTALL_HOST:-0.0.0.0} PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_REMOTE_INSTALL_HOST:-0.0.0.0}
PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_REMOTE_INSTALL_PORT:-5003} PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_REMOTE_INSTALL_PORT:-5002}
PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true} FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
ports: PLUGIN_PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
- "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
network_mode: "host"
volumes: volumes:
- /mnt/ramdisk/plugin_daemon:/app/storage - /mnt/ramdisk/plugin_daemon:/app/storage
- /etc/resolv.conf:/etc/resolv.conf
dns:
- 1.1.1.1
- 8.8.8.8
# ssrf_proxy server # ssrf_proxy server

View File

@@ -591,10 +591,12 @@ WORKFLOW_FILE_UPLOAD_LIMIT=10
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760 HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576 HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
# 指向 Amd64-02
#SSRF_PROXY_ALL_URL=socks5://10.0.0.246:2234
# SSRF Proxy server HTTP URL # SSRF Proxy server HTTP URL
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128 SSRF_PROXY_HTTP_URL=http://10.0.0.246:1234
# SSRF Proxy server HTTPS URL # SSRF Proxy server HTTPS URL
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128 SSRF_PROXY_HTTPS_URL=http://10.0.0.246:2234
# ------------------------------ # ------------------------------
# Environment Variables for web Service # Environment Variables for web Service
@@ -716,7 +718,7 @@ DB_PLUGIN_DATABASE=dify_plugin
EXPOSE_PLUGIN_DAEMON_PORT=5002 EXPOSE_PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_PORT=5002 PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DAEMON_URL=http://plugin_daemon:5002 PLUGIN_DAEMON_URL=http://10.0.0.12:5002
PLUGIN_MAX_PACKAGE_SIZE=52428800 PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_PPROF_ENABLED=false PLUGIN_PPROF_ENABLED=false
@@ -726,7 +728,7 @@ EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003 EXPOSE_PLUGIN_DEBUGGING_PORT=5003
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DIFY_INNER_API_URL=http://api:5001 PLUGIN_DIFY_INNER_API_URL=http://10.0.0.12:5001
ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id} ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id}
@@ -734,3 +736,8 @@ MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai MARKETPLACE_API_URL=https://marketplace.dify.ai
FORCE_VERIFYING_SIGNATURE=true FORCE_VERIFYING_SIGNATURE=true
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_MAX_EXECUTION_TIMEOUT=600
# PIP_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple
PIP_MIRROR_URL=

View File

@@ -53,7 +53,17 @@ services:
ports: ports:
- 8080:8080 - 8080:8080
redis:
image: redis:6-alpine
restart: always
environment:
REDISCLI_AUTH: ${REDIS_PASSWORD:-V2rayStrP@ss}
volumes:
# Mount the redis data directory to the container.
- /mnt/ramdisk/redis/data:/data
# Set the redis password when startup redis server.
command: redis-server --requirepass ${REDIS_PASSWORD:-V2rayStrP@ss}
healthcheck:
test: [ 'CMD', 'redis-cli', 'ping' ]
ports:
- 6379:6379

View File

@@ -1,8 +1,14 @@
#!/bin/bash #!/bin/bash
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer T7LxBemfe8SNGWkT9uz2XIc1e22ifAbBv_POJvDP" \
-H "Content-Type:application/json"
#export DOMAIN_NAME=chat.107421.xyz #export DOMAIN_NAME=chat.107421.xyz
export DOMAIN_NAME=push.107421.xyz export DOMAIN_NAME=push.107421.xyz
# 可以操作DNS的API Token
export CF_Token="oXJRP5XI8Zhipa_PtYtB_jy6qWL0I9BosrJEYE8p" export CF_Token="oXJRP5XI8Zhipa_PtYtB_jy6qWL0I9BosrJEYE8p"
export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191" export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191"
export CF_Zone_ID="511894a4f1357feb905e974e16241ebb" export CF_Zone_ID="511894a4f1357feb905e974e16241ebb"

View File

@@ -1,38 +0,0 @@
{
"listen": "0.0.0.0",
"port": 29999,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "RoMoH00dOl3zaQjdUKB6W0SS-wDYENgI3I7cREYwp1M",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"dest": "speed.cloudflare.com",
"serverNames": [
"speed.cloudflare.com"
],
"privateKey": "yNsDptp-3i-KqhLHA-RBLrVlJuiYeDUekirp-fkerQA",
"shortIds": [
"abc124cc",
"666asdcd"
]
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls",
"quic"
],
"routeOnly": true
}
}
}

View File

@@ -0,0 +1,82 @@
{
"log": {
"loglevel": "info"
},
"inbounds": [
{
"port": 24443,
"protocol": "vless",
"tag": "proxy",
"settings": {
"clients": [
{
"id": "f8702759-f402-4e85-92a6-8540d577de22",
"flow": "xtls-rprx-vision",
"email": "cc@vless.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "proxy"
}
],
"routing": {
"domainStrategy": "AsIs",
"domainMatcher": "hybrid",
"rules": [
{
"type": "field",
"inboundTag": [
"proxy"
],
"outboundTag": "proxy"
}
]
}
}

View File

@@ -0,0 +1,84 @@
{
"inbounds": [
{
"port": 24444,
"protocol": "vless",
"tag": "fv-ge-frk",
"settings": {
"clients": [
{
"id": "6055eac4-dee7-463b-b575-d30ea94bb768",
"flow": "xtls-rprx-vision",
"email": "franklin@vless.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fv-ge-frk",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "de-01.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fv-ge-frk"
],
"outboundTag": "fv-ge-frk"
}
]
}
}

View File

@@ -0,0 +1,84 @@
{
"inbounds": [
{
"port": 24445,
"protocol": "vless",
"tag": "fv-kr-sel",
"settings": {
"clients": [
{
"id": "1cd284b2-d3d8-4165-b773-893f836c2b51",
"flow": "xtls-rprx-vision",
"email": "seoul@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fv-kr-sel",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "kr.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fv-kr-sel"
],
"outboundTag": "fv-kr-sel"
}
]
}
}

View File

@@ -0,0 +1,84 @@
{
"inbounds": [
{
"port": 24446,
"protocol": "vless",
"tag": "fv-jp-tyk",
"settings": {
"clients": [
{
"id": "bf0e9c35-84a9-460e-b5bf-2fa9f2fb3bca",
"flow": "xtls-rprx-vision",
"email": "seoul@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fv-jp-tyk",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "jpjp.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fv-jp-tyk"
],
"outboundTag": "fv-jp-tyk"
}
]
}
}

View File

@@ -0,0 +1,85 @@
{
"inbounds": [
{
"port": 24447,
"protocol": "vless",
"tag": "fv-uk-lon",
"settings": {
"clients": [
{
"id": "adc19390-373d-4dfc-b0f6-19fab1b6fbf6",
"flow": "xtls-rprx-vision",
"email": "london@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fv-uk-lon",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "uk-02.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fv-uk-lon"
],
"outboundTag": "fv-uk-lon"
}
]
}
}

View File

@@ -0,0 +1,85 @@
{
"inbounds": [
{
"port": 24448,
"protocol": "vless",
"tag": "fv-sgp",
"settings": {
"clients": [
{
"id": "e31bc28e-8ebd-4d72-a98e-9227f26dfac3",
"flow": "xtls-rprx-vision",
"email": "singapore@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fv-sgp",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "sg-01.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fv-sgp"
],
"outboundTag": "fv-sgp"
}
]
}
}

View File

@@ -0,0 +1,85 @@
{
"inbounds": [
{
"port": 24452,
"protocol": "vless",
"tag": "fastestvpm-hongkong",
"settings": {
"clients": [
{
"id": "cdf0b19a-9524-48d5-b697-5f10bb567734",
"flow": "xtls-rprx-vision",
"email": "hongkong@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "wireguard",
"tag": "fastestvpm-hongkong",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": ["172.16.145.79/32"],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "hk.jumptoserver.com:51820"
}
]
}
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": [
"fastestvpm-hongkong"
],
"outboundTag": "fastestvpm-hongkong"
}
]
}
}

View File

@@ -0,0 +1,861 @@
{
"log": {
"loglevel": "error"
},
"inbounds": [
{
"port": 24443,
"protocol": "vless",
"tag": "proxy",
"settings": {
"clients": [
{
"id": "f8702759-f402-4e85-92a6-8540d577de22",
"flow": "xtls-rprx-vision",
"email": "cc@vless.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24444,
"protocol": "vless",
"tag": "fv-ge-frk",
"settings": {
"clients": [
{
"id": "6055eac4-dee7-463b-b575-d30ea94bb768",
"flow": "xtls-rprx-vision",
"email": "franklin@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24445,
"protocol": "vless",
"tag": "fv-kr-sel",
"settings": {
"clients": [
{
"id": "1cd284b2-d3d8-4165-b773-893f836c2b51",
"flow": "xtls-rprx-vision",
"email": "seoul@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24446,
"protocol": "vless",
"tag": "fv-jp-tyk",
"settings": {
"clients": [
{
"id": "bf0e9c35-84a9-460e-b5bf-2fa9f2fb3bca",
"flow": "xtls-rprx-vision",
"email": "tokyo@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24447,
"protocol": "vless",
"tag": "fv-uk-lon",
"settings": {
"clients": [
{
"id": "adc19390-373d-4dfc-b0f6-19fab1b6fbf6",
"flow": "xtls-rprx-vision",
"email": "london@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24448,
"protocol": "vless",
"tag": "fv-sgp",
"settings": {
"clients": [
{
"id": "e31bc28e-8ebd-4d72-a98e-9227f26dfac3",
"flow": "xtls-rprx-vision",
"email": "singapore@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24449,
"protocol": "vless",
"tag": "oracle-seoul-amd04",
"settings": {
"clients": [
{
"id": "7e27da0c-3013-4ed4-817b-50cc76a0bf81",
"flow": "xtls-rprx-vision",
"email": "seoul@oracle.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24450,
"protocol": "vless",
"tag": "fv-usa-losangles",
"settings": {
"clients": [
{
"id": "56fb312c-bdb0-48ca-bf66-4a2dd34040c6",
"flow": "xtls-rprx-vision",
"email": "losangles@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24451,
"protocol": "vless",
"tag": "care-germany-dusseldorf",
"settings": {
"clients": [
{
"id": "9fa9b4e7-d76d-4890-92cf-ce9251a76f59",
"flow": "xtls-rprx-vision",
"email": "dusseldorf@care.io",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24452,
"protocol": "vless",
"tag": "fastestvpn-hongkong",
"settings": {
"clients": [
{
"id": "cdf0b19a-9524-48d5-b697-5f10bb567734",
"flow": "xtls-rprx-vision",
"email": "hongkong@fastestvpn.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"port": 24453,
"protocol": "vless",
"tag": "cloudflare-hongkong",
"settings": {
"clients": [
{
"id": "93be1d17-8e02-449d-bb99-683ed46fbe50",
"flow": "xtls-rprx-vision",
"email": "hongkong@cloudflare.com",
"level": 0
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "/dev/shm/h2c.sock",
"xver": 2,
"alpn": "h2"
},
{
"dest": "/dev/shm/h1.sock",
"xver": 2
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"certificates": [
{
"ocspStapling": 3600,
"certificateFile": "/root/.acme.sh/book.107421.xyz_ecc/fullchain.cer",
"keyFile": "/root/.acme.sh/book.107421.xyz_ecc/book.107421.xyz.key"
}
],
"minVersion": "1.2",
"cipherSuites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"alpn": [
"h2",
"http/1.1"
]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "proxy"
},
{
"protocol": "wireguard",
"tag": "fv-ge-frk",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "de-01.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fv-kr-sel",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "kr.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fv-jp-tyk",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "jpjp.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fv-uk-lon",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "uk-02.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fv-sgp",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "sg-pro.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fv-usa-losangles",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "us-la-pro.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "wireguard",
"tag": "fastestvpn-hongkong",
"settings": {
"secretKey": "2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=",
"address": [
"172.16.145.79/32"
],
"peers": [
{
"publicKey": "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
"endpoint": "hk.jumptoserver.com:51820"
}
]
}
},
{
"protocol": "socks",
"tag": "cloudflare-hongkong",
"settings":{
"servers": [
{
"address": "127.0.0.1",
"port": 7990,
"level": 0
}
]
}
},
{
"protocol": "vless",
"tag": "oracle-seoul-amd04",
"settings": {
"vnext": [
{
"address": "140.238.14.103",
"port": 443,
"users": [
{
"id": "1089cc14-557e-47ac-ac85-c07957b3cce3",
"encryption": "none",
"flow": "xtls-rprx-vision",
"level": 0
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "xx.s4.cc.hh.107421.xyz"
}
}
},
{
"protocol": "vless",
"tag": "care-germany-dusseldorf",
"settings": {
"vnext": [
{
"address": "45.134.50.233",
"port": 443,
"users": [
{
"id": "b1417d92-998d-410b-a5f3-cf144b6f043e",
"encryption": "none",
"flow": "xtls-rprx-vision",
"level": 0
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"serverName": "bingo.107421.xyz"
}
}
}
],
"routing": {
"domainStrategy": "AsIs",
"domainMatcher": "hybrid",
"rules": [
{
"type": "field",
"inboundTag": [
"proxy"
],
"outboundTag": "proxy"
},
{
"type": "field",
"inboundTag": [
"cloudflare-hongkong"
],
"outboundTag": "cloudflare-hongkong"
},
{
"type": "field",
"inboundTag": [
"fv-ge-frk"
],
"outboundTag": "fv-ge-frk"
},
{
"type": "field",
"inboundTag": [
"fv-kr-sel"
],
"outboundTag": "fv-kr-sel"
},
{
"type": "field",
"inboundTag": [
"fv-jp-tyk"
],
"outboundTag": "fv-jp-tyk"
},
{
"type": "field",
"inboundTag": [
"fv-uk-lon"
],
"outboundTag": "fv-uk-lon"
},
{
"type": "field",
"inboundTag": [
"fv-sgp"
],
"outboundTag": "fv-sgp"
},
{
"type": "field",
"inboundTag": [
"fv-usa-losangles"
],
"outboundTag": "fv-usa-losangles"
},
{
"type": "field",
"inboundTag": [
"fastestvpn-hongkong"
],
"outboundTag": "fastestvpn-hongkong"
},
{
"type": "field",
"inboundTag": [
"oracle-seoul-amd04"
],
"outboundTag": "oracle-seoul-amd04"
},
{
"type": "field",
"inboundTag": [
"care-germany-dusseldorf"
],
"outboundTag": "care-germany-dusseldorf"
}
]
}
}

View File

@@ -6,6 +6,7 @@
{ {
"port": 24443, "port": 24443,
"protocol": "vless", "protocol": "vless",
"tag": "proxy",
"settings": { "settings": {
"clients": [ "clients": [
{ {
@@ -59,6 +60,23 @@
"outbounds": [ "outbounds": [
{ {
"protocol": "freedom" "protocol": "freedom"
},
{
"protocol": "freedom",
"tag": "proxy"
} }
] ],
"routing": {
"domainStrategy": "AsIs",
"domainMatcher": "hybrid",
"rules": [
{
"type": "field",
"inboundTag": [
"proxy"
],
"outboundTag": "proxy"
}
]
}
} }

View File

@@ -0,0 +1,72 @@
{
"inbounds": [
{
"protocol": "http",
"port": 2234,
"listen": "0.0.0.0",
"tag": "proxy-http"
},
{
"tag": "proxy",
"protocol": "socks",
"listen": "0.0.0.0",
"port": 1234,
"settings": {
"auth": "noauth",
"udp": true,
"ip": "127.0.0.1",
"userLevel": 0
}
},
{
"protocol": "socks",
"tag": "cloudflare",
"listen": "0.0.0.0",
"port": 1235,
"settings": {
"auth": "noauth",
"udp": true,
"userLevel": 0
}
}
],
"outbounds": [
{
"tag": "cloudflare",
"protocol": "socks",
"settings": {
"servers": [
{
"address": "127.0.0.1",
"port": 40000,
"level": 0
}
]
}
},
{
"tag": "proxy",
"protocol": "freedom"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"cloudflare",
"proxy-http"
],
"outboundTag": "cloudflare"
},
{
"type": "field",
"inboundTag": [
"proxy"
],
"outboundTag": "proxy"
}
]
}
}

View File

@@ -53,40 +53,260 @@ dns:
'+.ops.uavcmlc.com': '192.168.34.40' '+.ops.uavcmlc.com': '192.168.34.40'
proxies: proxies:
- {"type":"vmess","name":"us-central-free","ws-opts":{"path":"/vmess"},"server":"northflank.107421.xyz","port":443,"uuid":"de04add9-5c68-8bab-950c-08cd5320df18","alterId":0,"cipher":"auto","network":"ws","tls":true}
- type: vless
name: TC-HongKong
server: 43.154.83.213
port: 24443
uuid: f8702759-f402-4e85-92a6-8540d577de22
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: CF-HongKong-R-TCHK
server: 43.154.83.213
port: 24453
uuid: 93be1d17-8e02-449d-bb99-683ed46fbe50
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-HongKong
server: 43.154.83.213
port: 24452
uuid: cdf0b19a-9524-48d5-b697-5f10bb567734
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: Care-DEU-Dusseldorf-R-TCHK
server: 43.154.83.213
port: 24451
uuid: 9fa9b4e7-d76d-4890-92cf-ce9251a76f59
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: Care-DEU-Dusseldorf
server: 45.134.50.233
port: 443
uuid: b1417d92-998d-410b-a5f3-cf144b6f043e
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: bingo.107421.xyz
tls: true
udp: true
- type: vless
name: Oracle-KOR-Seoul
server: 140.238.14.103
port: 443
uuid: 1089cc14-557e-47ac-ac85-c07957b3cce3
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: xx.s4.cc.hh.107421.xyz
tls: true
udp: true
- name: CF_VIDEO_1
type: vless
server: bingo.pp.icederce.ip-ddns.com
port: 8443
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
udp: false
tls: true
network: ws
servername: pp.icederce.ip-ddns.com
ws-opts:
path: "/?ed=2560"
headers:
Host: pp.icederce.ip-ddns.com
- name: CF_VIDEO_2
type: vless
server: bingo.icederce.ip-ddns.com
port: 8443
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
udp: false
tls: true
network: ws
servername: pp.icederce.ip-ddns.com
ws-opts:
path: "/?ed=2560"
headers:
Host: pp.icederce.ip-ddns.com
- type: vless
name: FV-DEU-Frankfurt
server: 43.154.83.213
port: 24444
uuid: 6055eac4-dee7-463b-b575-d30ea94bb768
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-KOR-Seoul
server: 43.154.83.213
port: 24445
uuid: 1cd284b2-d3d8-4165-b773-893f836c2b51
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-JPN-Tokyo
server: 43.154.83.213
port: 24446
uuid: bf0e9c35-84a9-460e-b5bf-2fa9f2fb3bca
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-GBR-London
server: 43.154.83.213
port: 24447
uuid: adc19390-373d-4dfc-b0f6-19fab1b6fbf6
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-SGP
server: 43.154.83.213
port: 24448
uuid: e31bc28e-8ebd-4d72-a98e-9227f26dfac3
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: Oracle-KOR-Seoul-R-TCHK
server: 43.154.83.213
port: 24449
uuid: 7e27da0c-3013-4ed4-817b-50cc76a0bf81
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: vless
name: FV-USA-LosAngles
server: 43.154.83.213
port: 24450
uuid: 56fb312c-bdb0-48ca-bf66-4a2dd34040c6
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: book.107421.xyz
tls: true
udp: true
- type: socks5
name: TC-CHN-Shanghai
server: 42.192.52.227
port: 22887
username: zeaslity
password: a1f090ea-e39c-49e7-a3be-9af26b6ce563
udp: true
- type: vless
name: Oracle-JPN-Tokyo-R-OSel
server: 140.238.14.103
port: 20443
uuid: 21dab95b-088e-47bd-8351-609fd23cb33c
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: xx.t2.ll.c0.107421.xyz
tls: true
udp: true
- type: vless
name: Oracle-JPN-Osaka-R-OSel
server: 140.238.14.103
port: 21443
uuid: 4c2dd763-56e5-408f-bc8f-dbf4c1fe41f9
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: xx.o1.vl.s4.107421.xyz
tls: true
udp: true
- type: vless
name: Oracle-USA-Phoneix-R-OSel
server: 140.238.14.103
port: 22443
uuid: de576486-e254-4d9d-949a-37088358ec23
skip-cert-verify: false
network: tcp
flow: xtls-rprx-vision
servername: xx.p2.vl.s4.107421.xyz
tls: true
udp: true
- {"type":"socks5","name":"onetools-35-71","server":"192.168.35.71","port":22888,"username":"zeaslity","password":"password","udp":true} - {"type":"socks5","name":"onetools-35-71","server":"192.168.35.71","port":22888,"username":"zeaslity","password":"password","udp":true}
- {"type":"socks5","name":"TC-SH","server":"42.192.52.227","port":22887,"username":"zeaslity","password":"a1f090ea-e39c-49e7-a3be-9af26b6ce563","udp":true}
- {"type":"socks5","name":"TC-SH-LosA-BanH","server":"42.192.52.227","port":22888,"username":"zeaslity","password":"a1f090ea-e39c-49e7-a3be-9af26b6ce563","udp":true}
- {"type":"socks5","name":"TC-SH-Germany","server":"42.192.52.227","port":22889,"username":"zeaslity","password":"a1f090ea-e39c-49e7-a3be-9af26b6ce563","udp":true}
- {"type":"vless","name":"TC-HK-Vless","server":"43.154.83.213","port":24443,"uuid":"f8702759-f402-4e85-92a6-8540d577de22","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"book.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Care-Germany-Vless","server":"45.134.50.233","port":443,"uuid":"b1417d92-998d-410b-a5f3-cf144b6f043e","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"bingo.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Oracle-Seoul-ARM01-Vless","server":"132.145.87.10","port":443,"uuid":"1089cc14-557e-47ac-ac85-c07957b3cce3","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"xx.s0.yy.ac.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Oracle-Seoul-Vless","server":"140.238.14.103","port":443,"uuid":"1089cc14-557e-47ac-ac85-c07957b3cce3","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"xx.s4.cc.hh.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"BanH-LosA-Vless","server":"89.208.251.209","port":443,"uuid":"0c5741d0-76a9-4945-9c1d-14647afcce24","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"octopus.107421.xyz","tls":true,"udp":true}
- {"type":"trojan","name":"BanH-LosA-Trojan","server":"89.208.251.209","port":443,"password":"Vad3.123acasd-1234-as.dAsd.asdazzS.123","udp":true,"skip-cert-verify":false,"sni":"xx.l4.cc.nn.107421.xyz","network":"h2","ws-opts":{"path":"status","headers":{"host":"xx.l4.cc.nn.107421.xyz"}}}
- {"type":"vless","name":"Oracle-Tokyo-By-Seoul-Vless","server":"140.238.14.103","port":20443,"uuid":"21dab95b-088e-47bd-8351-609fd23cb33c","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"xx.t2.ll.c0.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Oracle-Osaka-By-Seoul-Vless","server":"140.238.14.103","port":21443,"uuid":"4c2dd763-56e5-408f-bc8f-dbf4c1fe41f9","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"xx.o1.vl.s4.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Oracle-Phoneix-By-Seoul-Vless","server":"140.238.14.103","port":22443,"uuid":"de576486-e254-4d9d-949a-37088358ec23","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"xx.p2.vl.s4.107421.xyz","tls":true,"udp":true}
- {"type":"vless","name":"Oracle-Pheonix-ARM02-Vless","server":"129.146.57.94","port":443,"uuid":"12491d80-745c-4e26-a58b-edf584afb208","skip-cert-verify":false,"network":"tcp","flow":"xtls-rprx-vision","servername":"zc.p4.cc.xx.107421.xyz","tls":true,"udp":true}
proxy-groups: proxy-groups:
- name: 🚀 节点选择 - name: 🚀 节点选择
type: select type: select
proxies: proxies:
- TC-HK-Vless - TC-HongKong
- BanH-LosA-Vless - CF-HongKong-R-TCHK
- BanH-LosA-Trojan - FV-HongKong
- us-central-free - CF_VIDEO_1
- Oracle-Seoul-ARM01-Vless - CF_VIDEO_2
- Care-Germany-Vless - Care-DEU-Dusseldorf-R-TCHK
- TC-SH - Oracle-KOR-Seoul-R-TCHK
- TC-SH-LosA-BanH - Care-DEU-Dusseldorf
- TC-SH-Germany - Oracle-KOR-Seoul
- Oracle-Seoul-Vless - FV-DEU-Frankfurt
- Oracle-Tokyo-By-Seoul-Vless - FV-KOR-Seoul
- Oracle-Osaka-By-Seoul-Vless - FV-JPN-Tokyo
- Oracle-Phoneix-By-Seoul-Vless - FV-GBR-London
- Oracle-Pheonix-ARM02-Vless - FV-USA-LosAngles
- onetools-35-71 - FV-SGP
- Oracle-JPN-Tokyo-R-OSel
- Oracle-JPN-Osaka-R-OSel
- Oracle-USA-Phoneix-R-OSel
- TC-CHN-Shanghai
- ♻️ 自动选择 - ♻️ 自动选择
- DIRECT - DIRECT
- name: ♻️ 自动选择 - name: ♻️ 自动选择
@@ -95,74 +315,55 @@ proxy-groups:
interval: 300 interval: 300
tolerance: 50 tolerance: 50
proxies: proxies:
- BanH-LosA-Trojan - TC-HongKong
- us-central-free - Oracle-KOR-Seoul
- Oracle-Seoul-Vless - Care-DEU-Dusseldorf
- Oracle-Seoul-ARM01-Vless - Oracle-JPN-Tokyo-R-OSel
- Care-Germany-Vless - Oracle-JPN-Osaka-R-OSel
- Oracle-Tokyo-By-Seoul-Vless - Oracle-USA-Phoneix-R-OSel
- Oracle-Osaka-By-Seoul-Vless
- Oracle-Phoneix-By-Seoul-Vless
- Oracle-Pheonix-ARM02-Vless
- BanH-LosA-Vless
- TC-HK-Vless
- TC-SH-LosA-BanH
- name: 🌍 国外媒体 - name: 🌍 国外媒体
type: select type: select
proxies: proxies:
- 🚀 节点选择 - 🚀 节点选择
- ♻️ 自动选择 - ♻️ 自动选择
- 🎯 全球直连 - 🎯 全球直连
- BanH-LosA-Trojan - Oracle-KOR-Seoul
- us-central-free - Care-DEU-Dusseldorf
- Oracle-Seoul-Vless - TC-HongKong
- Oracle-Seoul-ARM01-Vless - Oracle-JPN-Tokyo-R-OSel
- Care-Germany-Vless - Oracle-JPN-Osaka-R-OSel
- BanH-LosA-Vless - Oracle-USA-Phoneix-R-OSel
- TC-HK-Vless
- Oracle-Tokyo-By-Seoul-Vless
- Oracle-Osaka-By-Seoul-Vless
- Oracle-Phoneix-By-Seoul-Vless
- Oracle-Pheonix-ARM02-Vless
- name: 📲 电报信息 - name: 📲 电报信息
type: select type: select
proxies: proxies:
- 🚀 节点选择 - 🚀 节点选择
- 🎯 全球直连 - 🎯 全球直连
- BanH-LosA-Trojan - Oracle-KOR-Seoul
- us-central-free - TC-HongKong
- Oracle-Seoul-Vless
- Oracle-Seoul-ARM01-Vless
- TC-HK-Vless
- name: Ⓜ️ 微软服务 - name: Ⓜ️ 微软服务
type: select type: select
proxies: proxies:
- 🎯 全球直连 - 🎯 全球直连
- 🚀 节点选择 - 🚀 节点选择
- BanH-LosA-Trojan - Oracle-KOR-Seoul
- Oracle-Seoul-Vless - TC-HongKong
- us-central-free
- Oracle-Seoul-ARM01-Vless
- TC-HK-Vless
- name: 🍎 苹果服务 - name: 🍎 苹果服务
type: select type: select
proxies: proxies:
- 🚀 节点选择 - 🚀 节点选择
- 🎯 全球直连 - 🎯 全球直连
- BanH-LosA-Trojan - Oracle-KOR-Seoul
- us-central-free - TC-HongKong
- Oracle-Seoul-Vless
- Oracle-Seoul-ARM01-Vless
- TC-HK-Vless
- name: 💩 工作直连 - name: 💩 工作直连
type: select type: select
proxies: proxies:
- DIRECT - DIRECT
- onetools-35-71
- name: 💩 工作代理 - name: 💩 工作代理
type: select type: select
proxies: proxies:
- DIRECT
- onetools-35-71 - onetools-35-71
- DIRECT
- name: 🎯 全球直连 - name: 🎯 全球直连
type: select type: select
proxies: proxies:
@@ -185,12 +386,8 @@ proxy-groups:
- 🚀 节点选择 - 🚀 节点选择
- 🎯 全球直连 - 🎯 全球直连
- ♻️ 自动选择 - ♻️ 自动选择
- TC-HK-Vless - TC-HongKong
- BanH-LosA-Trojan - Oracle-KOR-Seoul
- us-central-free
- Oracle-Seoul-Vless
- Oracle-Seoul-ARM01-Vless
rules: rules:
- DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连 - DOMAIN-SUFFIX,cdcyy.cn,💩 工作直连
- DOMAIN-SUFFIX,hq.cmcc,💩 工作直连 - DOMAIN-SUFFIX,hq.cmcc,💩 工作直连
@@ -203,6 +400,7 @@ rules:
- DOMAIN-SUFFIX,ip6-loopback,🎯 全球直连 - DOMAIN-SUFFIX,ip6-loopback,🎯 全球直连
- DOMAIN-SUFFIX,local,🎯 全球直连 - DOMAIN-SUFFIX,local,🎯 全球直连
- DOMAIN-SUFFIX,localhost,🎯 全球直连 - DOMAIN-SUFFIX,localhost,🎯 全球直连
- DOMAIN-SUFFIX,amap.com,🎯 全球直连
- IP-CIDR,10.0.0.0/8,🎯 全球直连,no-resolve - IP-CIDR,10.0.0.0/8,🎯 全球直连,no-resolve
- IP-CIDR,100.64.0.0/10,🎯 全球直连,no-resolve - IP-CIDR,100.64.0.0/10,🎯 全球直连,no-resolve
- IP-CIDR,127.0.0.0/8,🎯 全球直连,no-resolve - IP-CIDR,127.0.0.0/8,🎯 全球直连,no-resolve

View File

@@ -1,12 +1,30 @@
vmess://eyJ2IjoiMiIsInBzIjoidXMtY2VudGUtZnJlZSIsImFkZCI6Im5vcnRoZmxhbmsuMTA3NDIxLnh5eiIsInBvcnQiOjQ0MywiaWQiOiJkZTA0YWRkOS01YzY4LThiYWItOTUwYy0wOGNkNTMyMGRmMTgiLCJhaWQiOjAsInNjeSI6ImF1dG8iLCJuZXQiOiJ3cyIsInBhdGgiOiIvdm1lc3MiLCJ0bHMiOiJ0bHMifQ== socks5://zeaslity:a1f090ea-e39c-49e7-a3be-9af26b6ce563@42.192.52.227:22887
trojan://VaC3.123a-asd1234-asdasd.aAsDazzS.123@43.154.83.213:443?flow=xtls-rprx-vision&security=tls&sni=xx.tc.hk.go.107421.xyz&alpn=h2&fp=firefox&type=http&path=status#TC-HK-Trojan socks5://zeaslity:a1f090ea-e39c-49e7-a3be-9af26b6ce563@42.192.52.227:22888
vless://8c1b580b-c59d-4b89-b020-980fa947539f@43.154.83.213:443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=book.107421.xyz&alpn=h2%2Chttp%2F1.1&fp=firefox&type=tcp&headerType=none#TC-HK-Vless socks5://zeaslity:a1f090ea-e39c-49e7-a3be-9af26b6ce563@42.192.52.227:22889
vless://b1417d92-998d-410b-a5f3-cf144b6f043e@45.134.50.233:443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=bingo.107421.xyz&alpn=h2%2Chttp%2F1.1&fp=firefox&type=tcp&headerType=none#Care-Germany-Vless
vless://1089cc14-557e-47ac-ac85-c07957b3cce3@140.238.14.103:443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=xx.s4.cc.hh.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none&host=xx.s4.cc.hh.107421.xyz#Oracle-Seoul-Vless
vless://0c5741d0-76a9-4945-9c1d-14647afcce24@89.208.251.209:443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=octopus.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none#BanH-LosA-Vless
trojan://Vad3.123acasd-1234-as.dAsd.asdazzS.123@89.208.251.209:443?flow=xtls-rprx-vision&security=tls&sni=xx.l4.cc.nn.107421.xyz&alpn=h2&fp=firefox&type=http&host=xx.l4.cc.nn.107421.xyz&path=status#BanH-LosA-Trojan
vless://21dab95b-088e-47bd-8351-609fd23cb33c@140.238.14.103:20443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=xx.t2.ll.c0.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none&host=xx.t2.ll.c0.107421.xyz#Oracle-Tokyo-By-Seoul-Vless
vless://4c2dd763-56e5-408f-bc8f-dbf4c1fe41f9@140.238.14.103:21443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=xx.o1.vl.s4.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none&host=xx.o1.vl.s4.107421.xyz#Oracle-Osaka-By-Seoul-Vless
vless://de576486-e254-4d9d-949a-37088358ec23@140.238.14.103:22443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=xx.p2.vl.s4.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none&host=xx.p2.vl.s4.107421.xyz#Oracle-Phoneix-By-Seoul-Vless
vless://12491d80-745c-4e26-a58b-edf584afb208@129.146.57.94:443?encryption=none&flow=xtls-rprx-vision&security=tls&sni=zc.p4.cc.xx.107421.xyz&alpn=h2&fp=firefox&type=tcp&headerType=none#Oracle-Pheonix-ARM02-Vless
vless://f8702759-f402-4e85-92a6-8540d577de22@43.154.83.213:24443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#TC-HongKong
vless://93be1d17-8e02-449d-bb99-683ed46fbe50@43.154.83.213:24453?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#CF-HongKong-R-TCHK
vless://cdf0b19a-9524-48d5-b697-5f10bb567734@43.154.83.213:24452?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-HongKong
vless://86c50e3a-5b87-49dd-bd20-03c7f2735e40@bingo.pp.icederce.ip-ddns.com:8443?encryption=none&security=tls&type=ws&sni=pp.icederce.ip-ddns.com&host=pp.icederce.ip-ddns.com&path=/?ed=2560#CF_VIDEO_1
vless://86c50e3a-5b87-49dd-bd20-03c7f2735e40@bingo.icederce.ip-ddns.com:8443?encryption=none&security=tls&type=ws&sni=pp.icederce.ip-ddns.com&host=pp.icederce.ip-ddns.com&path=/?ed=2560#CF_VIDEO_2
vless://7e27da0c-3013-4ed4-817b-50cc76a0bf81@43.154.83.213:24449?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Oracle-KOR-Seoul-R-TCHK
vless://9fa9b4e7-d76d-4890-92cf-ce9251a76f59@43.154.83.213:24451?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#Care-DEU-Dusseldorf-R-TCHK
vless://b1417d92-998d-410b-a5f3-cf144b6f043e@45.134.50.233:443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=bingo.107421.xyz#Care-DEU-Dusseldorf
vless://1089cc14-557e-47ac-ac85-c07957b3cce3@140.238.14.103:443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.s4.cc.hh.107421.xyz#Oracle-KOR-Seoul
vless://6055eac4-dee7-463b-b575-d30ea94bb768@43.154.83.213:24444?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-DEU-Frankfurt
vless://1cd284b2-d3d8-4165-b773-893f836c2b51@43.154.83.213:24445?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-KOR-Seoul
vless://bf0e9c35-84a9-460e-b5bf-2fa9f2fb3bca@43.154.83.213:24446?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-JPN-Tokyo
vless://adc19390-373d-4dfc-b0f6-19fab1b6fbf6@43.154.83.213:24447?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-GBR-London
vless://e31bc28e-8ebd-4d72-a98e-9227f26dfac3@43.154.83.213:24448?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-SGP
vless://56fb312c-bdb0-48ca-bf66-4a2dd34040c6@43.154.83.213:24450?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=book.107421.xyz#FV-USA-LosAngles
vless://21dab95b-088e-47bd-8351-609fd23cb33c@140.238.14.103:20443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.t2.ll.c0.107421.xyz#Oracle-JPN-Tokyo-R-OSel
vless://4c2dd763-56e5-408f-bc8f-dbf4c1fe41f9@140.238.14.103:21443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.o1.vl.s4.107421.xyz#Oracle-JPN-Osaka-R-OSel
vless://de576486-e254-4d9d-949a-37088358ec23@140.238.14.103:22443?type=tcp&encryption=none&security=tls&path=%2f&flow=xtls-rprx-vision&sni=xx.p2.vl.s4.107421.xyz#Oracle-USA-Phoneix-R-OSel

View File

@@ -0,0 +1,27 @@
- name: CF_TEST_1
type: vless
server: gur.gov.ua
port: 8443
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
udp: false
tls: true
network: ws
servername: pp.icederce.ip-ddns.com
ws-opts:
path: "/?ed=2560"
headers:
Host: pp.icederce.ip-ddns.com
- name: CF_TEST_2
type: vless
server: www.csgo.com
port: 443
uuid: 86c50e3a-5b87-49dd-bd20-03c7f2735e40
udp: false
tls: true
network: ws
servername: pp.icederce.ip-ddns.com
ws-opts:
path: "/?ed=2560"
headers:
Host: pp.icederce.ip-ddns.com

View File

@@ -0,0 +1,772 @@
import { connect } from 'cloudflare:sockets';
let userID = '86c50e3a-5b87-49dd-bd20-03c7f2735e40';
let proxyIP = '';
// let socks5Address = 'zeaslity:cd28a746-283e-47cc-88f7-bb43d7f6b53a@140.238.8.73:28888';
let sock5User = "zeaslity"
let sock5Pass = "cd28a746-283e-47cc-88f7-bb43d7f6b53a"
let sock5Host = "140.238.8.73"
let sock5Port = 28888
let enableSocks = true;
let go2Socks5s = [
'*ttvnw.net',
'*tapecontent.net',
'*cloudatacdn.com',
'*.loadshare.org',
"whoer.net",
"whatismyipaddress.com",
"*.cloudflare.com",
"*.cloudflare.net",
"*.cloudflare.workers.dev",
"dnschecker.org",
"ip.sb",
"ipinfo.io"
];
const httpPorts = ["8080", "8880", "2052", "2082", "2086", "2095"];
let httpsPorts = ["2053", "2083", "2087", "2096", "8443"];
export default {
async fetch(request, env, ctx) {
try {
const UA = request.headers.get('User-Agent') || 'null';
const upgradeHeader = request.headers.get('Upgrade');
const url = new URL(request.url);
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Hello World! to ' + url);
}
// handle 请求
return await WddGoOverWSHandler(request);
} catch (err) {
let e = err;
return new Response(e.toString());
}
},
};
async function WddGoOverWSHandler(request) {
// @ts-ignore
const webSocketPair = new WebSocketPair();
const [client, webSocket] = Object.values(webSocketPair);
// 接受 WebSocket 连接
webSocket.accept();
let address = '';
let portWithRandomLog = '';
// 日志函数,用于记录连接信息
const log = (/** @type {string} */ info, /** @type {string | undefined} */ event) => {
console.log(`[${address}:${portWithRandomLog}] ${info}`, event || '');
};
// 获取早期数据头部,可能包含了一些初始化数据
const earlyDataHeader = request.headers.get('sec-websocket-protocol') || '';
// 创建一个可读的 WebSocket 流,用于接收客户端数据
const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log);
// 用于存储远程 Socket 的包装器
let remoteSocketWapper = {
value: null,
};
// 标记是否为 DNS 查询
let isDns = false;
// WebSocket 数据流向远程服务器的管道
readableWebSocketStream.pipeTo(new WritableStream({
async write(chunk, controller) {
if (isDns) {
// 如果是 DNS 查询,调用 DNS 处理函数
return await handleDNSQuery(chunk, webSocket, null, log);
}
if (remoteSocketWapper.value) {
// 如果已有远程 Socket直接写入数据
const writer = remoteSocketWapper.value.writable.getWriter()
await writer.write(chunk);
writer.releaseLock();
return;
}
// 处理 WddGo 协议头部
const {
hasError,
message,
addressType,
portRemote = 443,
addressRemote = '',
rawDataIndex,
WddGoVersion = new Uint8Array([0, 0]),
isUDP,
} = processWddGoHeader(chunk, userID);
// 设置地址和端口信息,用于日志
address = addressRemote;
portWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? 'udp ' : 'tcp '} `;
if (hasError) {
// 如果有错误,抛出异常
throw new Error(message);
return;
}
// 如果是 UDP 且端口不是 DNS 端口53则关闭连接
if (isUDP) {
if (portRemote === 53) {
isDns = true;
} else {
throw new Error('UDP 代理仅对 DNS53 端口)启用');
return;
}
}
// 构建 WddGo 响应头部
const WddGoResponseHeader = new Uint8Array([WddGoVersion[0], 0]);
// 获取实际的客户端数据
const rawClientData = chunk.slice(rawDataIndex);
if (isDns) {
// 如果是 DNS 查询,调用 DNS 处理函数
return handleDNSQuery(rawClientData, webSocket, WddGoResponseHeader, log);
}
// 处理 TCP 出站连接
log(`处理 TCP 出站连接 ${addressRemote}:${portRemote}`);
handleTCPOutBound(remoteSocketWapper, addressType, addressRemote, portRemote, rawClientData, webSocket, WddGoResponseHeader, log);
},
close() {
log(`readableWebSocketStream 已关闭`);
},
abort(reason) {
log(`readableWebSocketStream 已中止`, JSON.stringify(reason));
},
})).catch((err) => {
log('readableWebSocketStream 管道错误', err);
});
// 返回一个 WebSocket 升级的响应
return new Response(null, {
status: 101,
// @ts-ignore
webSocket: client,
});
}
async function handleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, WddGoResponseHeader, log,) {
async function useSocks5Pattern(address) {
if (go2Socks5s.includes(address) || go2Socks5s.includes(address)) return true;
return go2Socks5s.some(pattern => {
let regexPattern = pattern.replace(/\*/g, '.*');
let regex = new RegExp(`^${regexPattern}$`, 'i');
return regex.test(address);
});
}
async function connectAndWrite(address, port, socks = false) {
log(`connected to ${address}:${port}`);
//if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address)) address = `${atob('d3d3Lg==')}${address}${atob('LmlwLjA5MDIyNy54eXo=')}`;
// 如果指定使用 SOCKS5 代理,则通过 SOCKS5 协议连接;否则直接连接
const tcpSocket = socks ? await socks5Connect(addressType, address, port, log)
: connect({
hostname: address,
port: port,
});
remoteSocket.value = tcpSocket;
//log(`connected to ${address}:${port}`);
const writer = tcpSocket.writable.getWriter();
// 首次写入,通常是 TLS 客户端 Hello 消息
await writer.write(rawClientData);
writer.releaseLock();
return tcpSocket;
}
/**
* 重试函数:当 Cloudflare 的 TCP Socket 没有传入数据时,我们尝试重定向 IP
* 这可能是因为某些网络问题导致的连接失败
*/
async function retry() {
if (enableSocks) {
// 如果启用了 SOCKS5通过 SOCKS5 代理重试连接
tcpSocket = await connectAndWrite(addressRemote, portRemote, true);
} else {
// 使用代理 IP
proxyIP = '[2603:c022:8008:8923:88a0:5c7d:2bb6:6ed5]'
portRemote = 27443
tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote);
}
// 无论重试是否成功,都要关闭 WebSocket可能是为了重新建立连接
tcpSocket.closed.catch(error => {
console.log('retry tcpSocket closed error', error);
}).finally(() => {
safeCloseWebSocket(webSocket);
})
// 建立从远程 Socket 到 WebSocket 的数据流
remoteSocketToWS(tcpSocket, webSocket, WddGoResponseHeader, null, log);
}
let useSocks = false;
if (go2Socks5s.length > 0 && enableSocks) useSocks = await useSocks5Pattern(addressRemote);
// 首次尝试连接远程服务器
let tcpSocket = await connectAndWrite(addressRemote, portRemote, useSocks);
// 当远程 Socket 就绪时,将其传递给 WebSocket
// 建立从远程服务器到 WebSocket 的数据流,用于将远程服务器的响应发送回客户端
// 如果连接失败或无数据retry 函数将被调用进行重试
remoteSocketToWS(tcpSocket, webSocket, WddGoResponseHeader, retry, log);
}
function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {
// 标记可读流是否已被取消
let readableStreamCancel = false;
// 创建一个新的可读流
const stream = new ReadableStream({
// 当流开始时的初始化函数
start(controller) {
// 监听 WebSocket 的消息事件
webSocketServer.addEventListener('message', (event) => {
// 如果流已被取消,不再处理新消息
if (readableStreamCancel) {
return;
}
const message = event.data;
// 将消息加入流的队列中
controller.enqueue(message);
});
// 监听 WebSocket 的关闭事件
// 注意:这个事件意味着客户端关闭了客户端 -> 服务器的流
// 但是,服务器 -> 客户端的流仍然打开,直到在服务器端调用 close()
// WebSocket 协议要求在每个方向上都要发送单独的关闭消息,以完全关闭 Socket
webSocketServer.addEventListener('close', () => {
// 客户端发送了关闭信号,需要关闭服务器端
safeCloseWebSocket(webSocketServer);
// 如果流未被取消,则关闭控制器
if (readableStreamCancel) {
return;
}
controller.close();
});
// 监听 WebSocket 的错误事件
webSocketServer.addEventListener('error', (err) => {
log('WebSocket 服务器发生错误');
// 将错误传递给控制器
controller.error(err);
});
// 处理 WebSocket 0-RTT零往返时间的早期数据
// 0-RTT 允许在完全建立连接之前发送数据,提高了效率
const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader);
if (error) {
// 如果解码早期数据时出错,将错误传递给控制器
controller.error(error);
} else if (earlyData) {
// 如果有早期数据,将其加入流的队列中
controller.enqueue(earlyData);
}
},
// 当使用者从流中拉取数据时调用
pull(controller) {
// 这里可以实现反压机制
// 如果 WebSocket 可以在流满时停止读取,我们就可以实现反压
// 参考https://streams.spec.whatwg.org/#example-rs-push-backpressure
},
// 当流被取消时调用
cancel(reason) {
// 流被取消的几种情况:
// 1. 当管道的 WritableStream 有错误时,这个取消函数会被调用,所以在这里处理 WebSocket 服务器的关闭
// 2. 如果 ReadableStream 被取消,所有 controller.close/enqueue 都需要跳过
// 3. 但是经过测试,即使 ReadableStream 被取消controller.error 仍然有效
if (readableStreamCancel) {
return;
}
log(`可读流被取消,原因是 ${reason}`);
readableStreamCancel = true;
// 安全地关闭 WebSocket
safeCloseWebSocket(webSocketServer);
}
});
return stream;
}
/**
* 解析 WddGo 协议的头部数据
* @param { ArrayBuffer} WddGoBuffer WddGo 协议的原始头部数据
* @param {string} userID 用于验证的用户 ID
* @returns {Object} 解析结果,包括是否有错误、错误信息、远程地址信息等
*/
function processWddGoHeader(WddGoBuffer, userID) {
// 检查数据长度是否足够(至少需要 24 字节)
if (WddGoBuffer.byteLength < 24) {
return {
hasError: true,
message: 'invalid data',
};
}
// 解析 WddGo 协议版本(第一个字节)
const version = new Uint8Array(WddGoBuffer.slice(0, 1));
let isValidUser = false;
let isUDP = false;
// 验证用户 ID接下来的 16 个字节)
function isUserIDValid(userID, buffer) {
const userIDArray = new Uint8Array(buffer.slice(1, 17));
const userIDString = stringify(userIDArray);
return userIDString === userID
}
// 使用函数验证
isValidUser = isUserIDValid(userID, WddGoBuffer);
// 如果用户 ID 无效,返回错误
if (!isValidUser) {
return {
hasError: true,
message: `invalid user ${(new Uint8Array(WddGoBuffer.slice(1, 17)))}`,
};
}
// 获取附加选项的长度(第 17 个字节)
const optLength = new Uint8Array(WddGoBuffer.slice(17, 18))[0];
// 暂时跳过附加选项
// 解析命令(紧跟在选项之后的 1 个字节)
// 0x01: TCP, 0x02: UDP, 0x03: MUX多路复用
const command = new Uint8Array(
WddGoBuffer.slice(18 + optLength, 18 + optLength + 1)
)[0];
// 0x01 TCP
// 0x02 UDP
// 0x03 MUX
if (command === 1) {
// TCP 命令,不需特殊处理
} else if (command === 2) {
// UDP 命令
isUDP = true;
} else {
// 不支持的命令
return {
hasError: true,
message: `command ${command} is not support, command 01-tcp,02-udp,03-mux`,
};
}
// 解析远程端口大端序2 字节)
const portIndex = 18 + optLength + 1;
const portBuffer = WddGoBuffer.slice(portIndex, portIndex + 2);
// port is big-Endian in raw data etc 80 == 0x005d
const portRemote = new DataView(portBuffer).getUint16(0);
// 解析地址类型和地址
let addressIndex = portIndex + 2;
const addressBuffer = new Uint8Array(
WddGoBuffer.slice(addressIndex, addressIndex + 1)
);
// 地址类型1-IPv4(4字节), 2-域名(可变长), 3-IPv6(16字节)
const addressType = addressBuffer[0];
let addressLength = 0;
let addressValueIndex = addressIndex + 1;
let addressValue = '';
switch (addressType) {
case 1:
// IPv4 地址
addressLength = 4;
// 将 4 个字节转为点分十进制格式
addressValue = new Uint8Array(
WddGoBuffer.slice(addressValueIndex, addressValueIndex + addressLength)
).join('.');
break;
case 2:
// 域名
// 第一个字节是域名长度
addressLength = new Uint8Array(
WddGoBuffer.slice(addressValueIndex, addressValueIndex + 1)
)[0];
addressValueIndex += 1;
// 解码域名
addressValue = new TextDecoder().decode(
WddGoBuffer.slice(addressValueIndex, addressValueIndex + addressLength)
);
break;
case 3:
// IPv6 地址
addressLength = 16;
const dataView = new DataView(
WddGoBuffer.slice(addressValueIndex, addressValueIndex + addressLength)
);
// 每 2 字节构成 IPv6 地址的一部分
const ipv6 = [];
for (let i = 0; i < 8; i++) {
ipv6.push(dataView.getUint16(i * 2).toString(16));
}
addressValue = ipv6.join(':');
// seems no need add [] for ipv6
break;
default:
// 无效的地址类型
return {
hasError: true,
message: `invild addressType is ${addressType}`,
};
}
// 确保地址不为空
if (!addressValue) {
return {
hasError: true,
message: `addressValue is empty, addressType is ${addressType}`,
};
}
// 返回解析结果
return {
hasError: false,
addressRemote: addressValue, // 解析后的远程地址
addressType, // 地址类型
portRemote, // 远程端口
rawDataIndex: addressValueIndex + addressLength, // 原始数据的实际起始位置
WddGoVersion: version, // WddGo 协议版本
isUDP, // 是否是 UDP 请求
};
}
async function remoteSocketToWS(remoteSocket, webSocket, WddGoResponseHeader, retry, log) {
// 将数据从远程服务器转发到 WebSocket
let remoteChunkCount = 0;
let chunks = [];
/** @type {ArrayBuffer | null} */
let WddGoHeader = WddGoResponseHeader;
let hasIncomingData = false; // 检查远程 Socket 是否有传入数据
// 使用管道将远程 Socket 的可读流连接到一个可写流
await remoteSocket.readable
.pipeTo(
new WritableStream({
start() {
// 初始化时不需要任何操作
},
/**
* 处理每个数据块
* @param {Uint8Array} chunk 数据块
* @param {*} controller 控制器
*/
async write(chunk, controller) {
hasIncomingData = true; // 标记已收到数据
// remoteChunkCount++; // 用于流量控制,现在似乎不需要了
// 检查 WebSocket 是否处于开放状态
if (webSocket.readyState !== WS_READY_STATE_OPEN) {
controller.error(
'webSocket.readyState is not open, maybe close'
);
}
if (WddGoHeader) {
// 如果有 WddGo 响应头部,将其与第一个数据块一起发送
webSocket.send(await new Blob([WddGoHeader, chunk]).arrayBuffer());
WddGoHeader = null; // 清空头部,之后不再发送
} else {
// 直接发送数据块
// 以前这里有流量控制代码,限制大量数据的发送速率
// 但现在 Cloudflare 似乎已经修复了这个问题
// if (remoteChunkCount > 20000) {
// // cf one package is 4096 byte(4kb), 4096 * 20000 = 80M
// await delay(1);
// }
webSocket.send(chunk);
}
},
close() {
// 当远程连接的可读流关闭时
log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`);
// 不需要主动关闭 WebSocket因为这可能导致 HTTP ERR_CONTENT_LENGTH_MISMATCH 问题
// 客户端无论如何都会发送关闭事件
// safeCloseWebSocket(webSocket);
},
abort(reason) {
// 当远程连接的可读流中断时
console.error(`remoteConnection!.readable abort`, reason);
},
})
)
.catch((error) => {
// 捕获并记录任何异常
console.error(
`remoteSocketToWS has exception `,
error.stack || error
);
// 发生错误时安全地关闭 WebSocket
safeCloseWebSocket(webSocket);
});
// 处理 Cloudflare 连接 Socket 的特殊错误情况
// 1. Socket.closed 将有错误
// 2. Socket.readable 将关闭,但没有任何数据
if (hasIncomingData === false && retry) {
log(`retry`);
retry(); // 调用重试函数,尝试重新建立连接
}
}
/**
* 将 Base64 编码的字符串转换为 ArrayBuffer
*
* @param {string} base64Str Base64 编码的输入字符串
* @returns {{ earlyData: ArrayBuffer | undefined, error: Error | null }} 返回解码后的 ArrayBuffer 或错误
*/
function base64ToArrayBuffer(base64Str) {
// 如果输入为空,直接返回空结果
if (!base64Str) {
return { earlyData: undefined, error: null };
}
try {
// Go 语言使用了 URL 安全的 Base64 变体RFC 4648
// 这种变体使用 '-' 和 '_' 来代替标准 Base64 中的 '+' 和 '/'
// JavaScript 的 atob 函数不直接支持这种变体,所以我们需要先转换
base64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/');
// 使用 atob 函数解码 Base64 字符串
// atob 将 Base64 编码的 ASCII 字符串转换为原始的二进制字符串
const decode = atob(base64Str);
// 将二进制字符串转换为 Uint8Array
// 这是通过遍历字符串中的每个字符并获取其 Unicode 编码值0-255来完成的
const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0));
// 返回 Uint8Array 的底层 ArrayBuffer
// 这是实际的二进制数据,可以用于网络传输或其他二进制操作
return { earlyData: arryBuffer.buffer, error: null };
} catch (error) {
// 如果在任何步骤中出现错误(如非法 Base64 字符),则返回错误
return { earlyData: undefined, error };
}
}
/**
* 这不是真正的 UUID 验证,而是一个简化的版本
* @param {string} uuid 要验证的 UUID 字符串
* @returns {boolean} 如果字符串匹配 UUID 格式则返回 true否则返回 false
*/
function isValidUUID(uuid) {
// 定义一个正则表达式来匹配 UUID 格式
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
// 使用正则表达式测试 UUID 字符串
return uuidRegex.test(uuid);
}
// WebSocket 的两个重要状态常量
const WS_READY_STATE_OPEN = 1; // WebSocket 处于开放状态,可以发送和接收消息
const WS_READY_STATE_CLOSING = 2; // WebSocket 正在关闭过程中
function safeCloseWebSocket(socket) {
try {
// 只有在 WebSocket 处于开放或正在关闭状态时才调用 close()
// 这避免了在已关闭或连接中的 WebSocket 上调用 close()
if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) {
socket.close();
}
} catch (error) {
// 记录任何可能发生的错误,虽然按照规范不应该有错误
console.error('safeCloseWebSocket error', error);
}
}
// 预计算 0-255 每个字节的十六进制表示
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
// (i + 256).toString(16) 确保总是得到两位数的十六进制
// .slice(1) 删除前导的 "1",只保留两位十六进制数
byteToHex.push((i + 256).toString(16).slice(1));
}
/**
* 快速地将字节数组转换为 UUID 字符串,不进行有效性检查
* 这是一个底层函数,直接操作字节,不做任何验证
* @param {Uint8Array} arr 包含 UUID 字节的数组
* @param {number} offset 数组中 UUID 开始的位置,默认为 0
* @returns {string} UUID 字符串
*/
function unsafeStringify(arr, offset = 0) {
// 直接从查找表中获取每个字节的十六进制表示,并拼接成 UUID 格式
// 8-4-4-4-12 的分组是通过精心放置的连字符 "-" 实现的
// toLowerCase() 确保整个 UUID 是小写的
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" +
byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" +
byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" +
byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" +
byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] +
byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
}
/**
* 将字节数组转换为 UUID 字符串,并验证其有效性
* 这是一个安全的函数,它确保返回的 UUID 格式正确
* @param {Uint8Array} arr 包含 UUID 字节的数组
* @param {number} offset 数组中 UUID 开始的位置,默认为 0
* @returns {string} 有效的 UUID 字符串
* @throws {TypeError} 如果生成的 UUID 字符串无效
*/
function stringify(arr, offset = 0) {
// 使用不安全的函数快速生成 UUID 字符串
const uuid = unsafeStringify(arr, offset);
// 验证生成的 UUID 是否有效
if (!isValidUUID(uuid)) {
// 原throw TypeError("Stringified UUID is invalid");
throw TypeError(`生成的 UUID 不符合规范 ${uuid}`);
//uuid = userID;
}
return uuid;
}
/**
* 处理 DNS 查询的函数
* @param {ArrayBuffer} udpChunk - 客户端发送的 DNS 查询数据
* @param {ArrayBuffer} WddGoResponseHeader - WddGo 协议的响应头部数据
* @param {(string)=> void} log - 日志记录函数
*/
async function handleDNSQuery(udpChunk, webSocket, WddGoResponseHeader, log) {
// 无论客户端发送到哪个 DNS 服务器,我们总是使用硬编码的服务器
// 因为有些 DNS 服务器不支持 DNS over TCP
try {
// 选用 Google 的 DNS 服务器(注:后续可能会改为 Cloudflare 的 1.1.1.1
const dnsServer = '8.8.4.4'; // 在 Cloudflare 修复连接自身 IP 的 bug 后,将改为 1.1.1.1
const dnsPort = 53; // DNS 服务的标准端口
let WddGoHeader = WddGoResponseHeader; // 保存 WddGo 响应头部,用于后续发送
// 与指定的 DNS 服务器建立 TCP 连接
const tcpSocket = connect({
hostname: dnsServer,
port: dnsPort,
});
log(`连接到 ${dnsServer}:${dnsPort}`); // 记录连接信息
const writer = tcpSocket.writable.getWriter();
await writer.write(udpChunk); // 将客户端的 DNS 查询数据发送给 DNS 服务器
writer.releaseLock(); // 释放写入器,允许其他部分使用
// 将从 DNS 服务器接收到的响应数据通过 WebSocket 发送回客户端
await tcpSocket.readable.pipeTo(new WritableStream({
async write(chunk) {
if (webSocket.readyState === WS_READY_STATE_OPEN) {
if (WddGoHeader) {
// 如果有 WddGo 头部,则将其与 DNS 响应数据合并后发送
webSocket.send(await new Blob([WddGoHeader, chunk]).arrayBuffer());
WddGoHeader = null; // 头部只发送一次,之后置为 null
} else {
// 否则直接发送 DNS 响应数据
webSocket.send(chunk);
}
}
},
close() {
log(`DNS 服务器(${dnsServer}) TCP 连接已关闭`); // 记录连接关闭信息
},
abort(reason) {
console.error(`DNS 服务器(${dnsServer}) TCP 连接异常中断`, reason); // 记录异常中断原因
},
}));
} catch (error) {
// 捕获并记录任何可能发生的错误
console.error(
`handleDNSQuery 函数发生异常,错误信息: ${error.message}`
);
}
}
async function socks5Connect(addressType, addressRemote, portRemote, log) {
// 从环境变量获取认证信息(假设在运行环境中已定义)
const username = sock5User
const password = sock5Pass
const hostname = sock5Host
const port = sock5Port
// 直连代理服务器
const socket = connect({ hostname, port });
const writer = socket.writable.getWriter();
const reader = socket.readable.getReader();
const encoder = new TextEncoder();
// 精简握手流程:直接声明需要用户名密码认证
await writer.write(new Uint8Array([5, 1, 2])); // 只支持 0x02 方法
log('SOCKS5 认证方法协商');
// 处理认证响应
let res = (await reader.read()).value;
if (res[0] !== 0x05 || res[1] !== 0x02) {
res[1] === 0xff && log("不支持的认证方式");
return;
}
// 构造认证数据包(提前计算长度避免重复编码)
const userBytes = encoder.encode(username);
const passBytes = encoder.encode(password);
const authHeader = new Uint8Array(3 + userBytes.length + passBytes.length);
authHeader.set([1, userBytes.length, ...userBytes, passBytes.length], 0);
authHeader.set(passBytes, 2 + userBytes.length); // 优化内存拷贝
await writer.write(authHeader);
res = (await reader.read()).value;
if (res[0] !== 0x01 || res[1] !== 0x00) {
log(`认证失败 code: 0x${res[1].toString(16)}`);
return;
}
// 构造目标地址(优化二进制操作)
const header = new Uint8Array([5, 1, 0]);
const addrBuffer = new Uint8Array(
addressType === 3 ? 16 + 1 : // IPv6
addressType === 2 ? encoder.encode(addressRemote).length + 2 : // 域名
4 + 1 // IPv4
);
let offset = 0;
addrBuffer[offset++] = addressType === 3 ? 4 : addressType;
if (addressType === 2) {
addrBuffer[offset++] = addressRemote.length;
encoder.encodeInto(addressRemote, addrBuffer.subarray(offset));
} else {
const octets = addressType === 3 ?
new Uint16Array(addressRemote.split(':').flatMap(p =>
[parseInt(p.substring(0,4),16), parseInt(p.substring(4),16)])) :
addressRemote.split('.').map(Number);
addrBuffer.set(new Uint8Array(octets.buffer || octets), offset);
}
// 合并数据包并发送
const finalPacket = new Uint8Array([
...header,
...addrBuffer,
portRemote >> 8, portRemote & 0xff
]);
await writer.write(finalPacket);
log('SOCKS5 连接请求已发送');
// 验证最终响应
res = (await reader.read()).value;
if (res[1] !== 0x00) {
log(`连接失败 code: 0x${res[1].toString(16)}`);
return;
}
writer.releaseLock();
reader.releaseLock();
return socket;
}

View File

@@ -0,0 +1,996 @@
// @ts-ignore
import { connect } from "cloudflare:sockets";
let userID = "86c50e3a-5b87-49dd-bd20-03c7f2735e40";
const proxyIPs = ["ts.hpc.tw","47.254.66.75","146.70.175.98","146.70.175.99","146.70.175.100","146.70.175.101","146.70.175.102","146.70.175.103","146.70.175.104","146.70.175.106","cdn-all.xn--b6gac.eu.org","cdn.xn--b6gac.eu.org"];
const cn_hostnames = [''];
let CDNIP = 'cdn-all.xijingping.link'
// http_ip
let IP1 = 'www.visa.com'
let IP2 = 'cis.visa.com'
let IP3 = 'africa.visa.com'
let IP4 = 'www.visa.com.sg'
let IP5 = 'www.visaeurope.at'
let IP6 = 'www.visa.com.mt'
let IP7 = 'qa.visamiddleeast.com'
// https_ip
let IP8 = 'usa.visa.com'
let IP9 = 'malaysia.com'
let IP10 = 'www.visa.co.jp'
let IP11 = 'www.digitalocean.com'
let IP12 = 'japan.com'
let IP13 = 'cdn-b100.xn--b6gac.eu.org'
// http_port
let PT1 = '80'
let PT2 = '8080'
let PT3 = '8880'
let PT4 = '2052'
let PT5 = '2082'
let PT6 = '2086'
let PT7 = '2095'
// https_port
let PT8 = '443'
let PT9 = '8443'
let PT10 = '2053'
let PT11 = '2083'
let PT12 = '2087'
let PT13 = '2096'
let proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)];
let proxyPort = proxyIP.includes(':') ? proxyIP.split(':')[1] : '443';
if (!isValidUUID(userID)) {
throw new Error("uuid is not valid");
}
export default {
/**
* @param {import("@cloudflare/workers-types").Request} request
* @param {uuid: string, proxyip: string, cdnip: string, ip1: string, ip2: string, ip3: string, ip4: string, ip5: string, ip6: string, ip7: string, ip8: string, ip9: string, ip10: string, ip11: string, ip12: string, ip13: string, pt1: string, pt2: string, pt3: string, pt4: string, pt5: string, pt6: string, pt7: string, pt8: string, pt9: string, pt10: string, pt11: string, pt12: string, pt13: string} env
* @param {import("@cloudflare/workers-types").ExecutionContext} ctx
* @returns {Promise<Response>}
*/
async fetch(request, env, ctx) {
try {
const { proxyip } = env;
userID = env.uuid || userID;
if (proxyip) {
if (proxyip.includes(']:')) {
let lastColonIndex = proxyip.lastIndexOf(':');
proxyPort = proxyip.slice(lastColonIndex + 1);
proxyIP = proxyip.slice(0, lastColonIndex);
} else if (!proxyip.includes(']:') && !proxyip.includes(']')) {
[proxyIP, proxyPort = '443'] = proxyip.split(':');
} else {
proxyPort = '443';
proxyIP = proxyip;
}
} else {
if (proxyIP.includes(']:')) {
let lastColonIndex = proxyIP.lastIndexOf(':');
proxyPort = proxyIP.slice(lastColonIndex + 1);
proxyIP = proxyIP.slice(0, lastColonIndex);
} else if (!proxyIP.includes(']:') && !proxyIP.includes(']')) {
[proxyIP, proxyPort = '443'] = proxyIP.split(':');
} else {
proxyPort = '443';
}
}
console.log('ProxyIP:', proxyIP);
console.log('ProxyPort:', proxyPort);
CDNIP = env.cdnip || CDNIP;
IP1 = env.ip1 || IP1;
IP2 = env.ip2 || IP2;
IP3 = env.ip3 || IP3;
IP4 = env.ip4 || IP4;
IP5 = env.ip5 || IP5;
IP6 = env.ip6 || IP6;
IP7 = env.ip7 || IP7;
IP8 = env.ip8 || IP8;
IP9 = env.ip9 || IP9;
IP10 = env.ip10 || IP10;
IP11 = env.ip11 || IP11;
IP12 = env.ip12 || IP12;
IP13 = env.ip13 || IP13;
PT1 = env.pt1 || PT1;
PT2 = env.pt2 || PT2;
PT3 = env.pt3 || PT3;
PT4 = env.pt4 || PT4;
PT5 = env.pt5 || PT5;
PT6 = env.pt6 || PT6;
PT7 = env.pt7 || PT7;
PT8 = env.pt8 || PT8;
PT9 = env.pt9 || PT9;
PT10 = env.pt10 || PT10;
PT11 = env.pt11 || PT11;
PT12 = env.pt12 || PT12;
PT13 = env.pt13 || PT13;
const upgradeHeader = request.headers.get("Upgrade");
const url = new URL(request.url);
if (!upgradeHeader || upgradeHeader !== "websocket") {
// return new Response('Not found', { status: 404 });
// For any other path, reverse proxy to 'ramdom website' and return the original response, caching it in the process
if (cn_hostnames.includes('')) {
return new Response(JSON.stringify(request.cf, null, 4), {
status: 200,
headers: {
"Content-Type": "application/json;charset=utf-8",
},
});
}
const randomHostname = cn_hostnames[Math.floor(Math.random() * cn_hostnames.length)];
const newHeaders = new Headers(request.headers);
newHeaders.set("cf-connecting-ip", "1.2.3.4");
newHeaders.set("x-forwarded-for", "1.2.3.4");
newHeaders.set("x-real-ip", "1.2.3.4");
newHeaders.set("referer", "https://www.google.com/search?q=edtunnel");
// Use fetch to proxy the request to 15 different domains
const proxyUrl = "https://" + randomHostname + url.pathname + url.search;
let modifiedRequest = new Request(proxyUrl, {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: "manual",
});
const proxyResponse = await fetch(modifiedRequest, { redirect: "manual" });
// Check for 302 or 301 redirect status and return an error response
if ([301, 302].includes(proxyResponse.status)) {
return new Response(`Redirects to ${randomHostname} are not allowed.`, {
status: 403,
statusText: "Forbidden",
});
}
// Return the response from the proxy server
return proxyResponse;
} else {
return await vlessOverWSHandler(request);
}
} catch (err) {
/** @type {Error} */ let e = err;
return new Response(e.toString());
}
},
};
function isValidIP(ip) {
var reg = /^[\s\S]*$/;
return reg.test(ip);
}
/**
*
* @param {import("@cloudflare/workers-types").Request} request
*/
async function vlessOverWSHandler(request) {
/** @type {import("@cloudflare/workers-types").WebSocket[]} */
// @ts-ignore
const webSocketPair = new WebSocketPair();
const [client, webSocket] = Object.values(webSocketPair);
webSocket.accept();
let address = "";
let portWithRandomLog = "";
const log = (/** @type {string} */ info, /** @type {string | undefined} */ event) => {
console.log(`[${address}:${portWithRandomLog}] ${info}`, event || "");
};
const earlyDataHeader = request.headers.get("sec-websocket-protocol") || "";
const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log);
/** @type {{ value: import("@cloudflare/workers-types").Socket | null}}*/
let remoteSocketWapper = {
value: null,
};
let udpStreamWrite = null;
let isDns = false;
// ws --> remote
readableWebSocketStream
.pipeTo(
new WritableStream({
async write(chunk, controller) {
if (isDns && udpStreamWrite) {
return udpStreamWrite(chunk);
}
if (remoteSocketWapper.value) {
const writer = remoteSocketWapper.value.writable.getWriter();
await writer.write(chunk);
writer.releaseLock();
return;
}
const {
hasError,
message,
portRemote = 443,
addressRemote = "",
rawDataIndex,
vlessVersion = new Uint8Array([0, 0]),
isUDP,
} = await processVlessHeader(chunk, userID);
address = addressRemote;
portWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? "udp " : "tcp "} `;
if (hasError) {
// controller.error(message);
throw new Error(message); // cf seems has bug, controller.error will not end stream
// webSocket.close(1000, message);
return;
}
// if UDP but port not DNS port, close it
if (isUDP) {
if (portRemote === 53) {
isDns = true;
} else {
// controller.error('UDP proxy only enable for DNS which is port 53');
throw new Error("UDP proxy only enable for DNS which is port 53"); // cf seems has bug, controller.error will not end stream
return;
}
}
// ["version", "附加信息长度 N"]
const vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]);
const rawClientData = chunk.slice(rawDataIndex);
// TODO: support udp here when cf runtime has udp support
if (isDns) {
const { write } = await handleUDPOutBound(webSocket, vlessResponseHeader, log);
udpStreamWrite = write;
udpStreamWrite(rawClientData);
return;
}
handleTCPOutBound(
remoteSocketWapper,
addressRemote,
portRemote,
rawClientData,
webSocket,
vlessResponseHeader,
log
);
},
close() {
log(`readableWebSocketStream is close`);
},
abort(reason) {
log(`readableWebSocketStream is abort`, JSON.stringify(reason));
},
})
)
.catch((err) => {
log("readableWebSocketStream pipeTo error", err);
});
return new Response(null, {
status: 101,
// @ts-ignore
webSocket: client,
});
}
/**
* Checks if a given UUID is present in the API response.
* @param {string} targetUuid The UUID to search for.
* @returns {Promise<boolean>} A Promise that resolves to true if the UUID is present in the API response, false otherwise.
*/
async function checkUuidInApiResponse(targetUuid) {
// Check if any of the environment variables are empty
try {
const apiResponse = await getApiResponse();
if (!apiResponse) {
return false;
}
const isUuidInResponse = apiResponse.users.some((user) => user.uuid === targetUuid);
return isUuidInResponse;
} catch (error) {
console.error("Error:", error);
return false;
}
}
/**
* Handles outbound TCP connections.
*
* @param {any} remoteSocket
* @param {string} addressRemote The remote address to connect to.
* @param {number} portRemote The remote port to connect to.
* @param {Uint8Array} rawClientData The raw client data to write.
* @param {import("@cloudflare/workers-types").WebSocket} webSocket The WebSocket to pass the remote socket to.
* @param {Uint8Array} vlessResponseHeader The vless response header.
* @param {function} log The logging function.
* @returns {Promise<void>} The remote socket.
*/
async function handleTCPOutBound(
remoteSocket,
addressRemote,
portRemote,
rawClientData,
webSocket,
vlessResponseHeader,
log
) {
async function connectAndWrite(address, port) {
if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address)) address = `${atob('d3d3Lg==')}${address}${atob('LnNzbGlwLmlv')}`;
/** @type {import("@cloudflare/workers-types").Socket} */
const tcpSocket = connect({
hostname: address,
port: port,
});
remoteSocket.value = tcpSocket;
log(`connected to ${address}:${port}`);
const writer = tcpSocket.writable.getWriter();
await writer.write(rawClientData); // first write, nomal is tls client hello
writer.releaseLock();
return tcpSocket;
}
// if the cf connect tcp socket have no incoming data, we retry to redirect ip
async function retry() {
const tcpSocket = await connectAndWrite(proxyIP || addressRemote, proxyPort || portRemote);
// no matter retry success or not, close websocket
tcpSocket.closed
.catch((error) => {
console.log("retry tcpSocket closed error", error);
})
.finally(() => {
safeCloseWebSocket(webSocket);
});
remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log);
}
const tcpSocket = await connectAndWrite(addressRemote, portRemote);
// when remoteSocket is ready, pass to websocket
// remote--> ws
remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log);
}
/**
*
* @param {import("@cloudflare/workers-types").WebSocket} webSocketServer
* @param {string} earlyDataHeader for ws 0rtt
* @param {(info: string)=> void} log for ws 0rtt
*/
function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {
let readableStreamCancel = false;
const stream = new ReadableStream({
start(controller) {
webSocketServer.addEventListener("message", (event) => {
if (readableStreamCancel) {
return;
}
const message = event.data;
controller.enqueue(message);
});
// The event means that the client closed the client -> server stream.
// However, the server -> client stream is still open until you call close() on the server side.
// The WebSocket protocol says that a separate close message must be sent in each direction to fully close the socket.
webSocketServer.addEventListener("close", () => {
// client send close, need close server
// if stream is cancel, skip controller.close
safeCloseWebSocket(webSocketServer);
if (readableStreamCancel) {
return;
}
controller.close();
});
webSocketServer.addEventListener("error", (err) => {
log("webSocketServer has error");
controller.error(err);
});
// for ws 0rtt
const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader);
if (error) {
controller.error(error);
} else if (earlyData) {
controller.enqueue(earlyData);
}
},
pull(controller) {
// if ws can stop read if stream is full, we can implement backpressure
// https://streams.spec.whatwg.org/#example-rs-push-backpressure
},
cancel(reason) {
// 1. pipe WritableStream has error, this cancel will called, so ws handle server close into here
// 2. if readableStream is cancel, all controller.close/enqueue need skip,
// 3. but from testing controller.error still work even if readableStream is cancel
if (readableStreamCancel) {
return;
}
log(`ReadableStream was canceled, due to ${reason}`);
readableStreamCancel = true;
safeCloseWebSocket(webSocketServer);
},
});
return stream;
}
// https://xtls.github.io/development/protocols/vless.html
// https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw
/**
*
* @param { ArrayBuffer} vlessBuffer
* @param {string} userID
* @returns
*/
async function processVlessHeader(vlessBuffer, userID) {
if (vlessBuffer.byteLength < 24) {
return {
hasError: true,
message: "invalid data",
};
}
const version = new Uint8Array(vlessBuffer.slice(0, 1));
let isValidUser = false;
let isUDP = false;
const slicedBuffer = new Uint8Array(vlessBuffer.slice(1, 17));
const slicedBufferString = stringify(slicedBuffer);
const uuids = userID.includes(",") ? userID.split(",") : [userID];
const checkUuidInApi = await checkUuidInApiResponse(slicedBufferString);
isValidUser = uuids.some((userUuid) => checkUuidInApi || slicedBufferString === userUuid.trim());
console.log(`checkUuidInApi: ${await checkUuidInApiResponse(slicedBufferString)}, userID: ${slicedBufferString}`);
if (!isValidUser) {
return {
hasError: true,
message: "invalid user",
};
}
const optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0];
//skip opt for now
const command = new Uint8Array(vlessBuffer.slice(18 + optLength, 18 + optLength + 1))[0];
// 0x01 TCP
// 0x02 UDP
// 0x03 MUX
if (command === 1) {
} else if (command === 2) {
isUDP = true;
} else {
return {
hasError: true,
message: `command ${command} is not support, command 01-tcp,02-udp,03-mux`,
};
}
const portIndex = 18 + optLength + 1;
const portBuffer = vlessBuffer.slice(portIndex, portIndex + 2);
// port is big-Endian in raw data etc 80 == 0x005d
const portRemote = new DataView(portBuffer).getUint16(0);
let addressIndex = portIndex + 2;
const addressBuffer = new Uint8Array(vlessBuffer.slice(addressIndex, addressIndex + 1));
// 1--> ipv4 addressLength =4
// 2--> domain name addressLength=addressBuffer[1]
// 3--> ipv6 addressLength =16
const addressType = addressBuffer[0];
let addressLength = 0;
let addressValueIndex = addressIndex + 1;
let addressValue = "";
switch (addressType) {
case 1:
addressLength = 4;
addressValue = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)).join(".");
break;
case 2:
addressLength = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + 1))[0];
addressValueIndex += 1;
addressValue = new TextDecoder().decode(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength));
break;
case 3:
addressLength = 16;
const dataView = new DataView(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength));
// 2001:0db8:85a3:0000:0000:8a2e:0370:7334
const ipv6 = [];
for (let i = 0; i < 8; i++) {
ipv6.push(dataView.getUint16(i * 2).toString(16));
}
addressValue = ipv6.join(":");
// seems no need add [] for ipv6
break;
default:
return {
hasError: true,
message: `invild addressType is ${addressType}`,
};
}
if (!addressValue) {
return {
hasError: true,
message: `addressValue is empty, addressType is ${addressType}`,
};
}
return {
hasError: false,
addressRemote: addressValue,
addressType,
portRemote,
rawDataIndex: addressValueIndex + addressLength,
vlessVersion: version,
isUDP,
};
}
/**
*
* @param {import("@cloudflare/workers-types").Socket} remoteSocket
* @param {import("@cloudflare/workers-types").WebSocket} webSocket
* @param {ArrayBuffer} vlessResponseHeader
* @param {(() => Promise<void>) | null} retry
* @param {*} log
*/
async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) {
// remote--> ws
let remoteChunkCount = 0;
let chunks = [];
/** @type {ArrayBuffer | null} */
let vlessHeader = vlessResponseHeader;
let hasIncomingData = false; // check if remoteSocket has incoming data
await remoteSocket.readable
.pipeTo(
new WritableStream({
start() {},
/**
*
* @param {Uint8Array} chunk
* @param {*} controller
*/
async write(chunk, controller) {
hasIncomingData = true;
// remoteChunkCount++;
if (webSocket.readyState !== WS_READY_STATE_OPEN) {
controller.error("webSocket.readyState is not open, maybe close");
}
if (vlessHeader) {
webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer());
vlessHeader = null;
} else {
// seems no need rate limit this, CF seems fix this??..
// if (remoteChunkCount > 20000) {
// // cf one package is 4096 byte(4kb), 4096 * 20000 = 80M
// await delay(1);
// }
webSocket.send(chunk);
}
},
close() {
log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`);
// safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway.
},
abort(reason) {
console.error(`remoteConnection!.readable abort`, reason);
},
})
)
.catch((error) => {
console.error(`remoteSocketToWS has exception `, error.stack || error);
safeCloseWebSocket(webSocket);
});
// seems is cf connect socket have error,
// 1. Socket.closed will have error
// 2. Socket.readable will be close without any data coming
if (hasIncomingData === false && retry) {
log(`retry`);
retry();
}
}
/**
*
* @param {string} base64Str
* @returns
*/
function base64ToArrayBuffer(base64Str) {
if (!base64Str) {
return { error: null };
}
try {
// go use modified Base64 for URL rfc4648 which js atob not support
base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");
const decode = atob(base64Str);
const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0));
return { earlyData: arryBuffer.buffer, error: null };
} catch (error) {
return { error };
}
}
/**
* This is not real UUID validation
* @param {string} uuid
*/
function isValidUUID(uuid) {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return uuidRegex.test(uuid);
}
const WS_READY_STATE_OPEN = 1;
const WS_READY_STATE_CLOSING = 2;
/**
* Normally, WebSocket will not has exceptions when close.
* @param {import("@cloudflare/workers-types").WebSocket} socket
*/
function safeCloseWebSocket(socket) {
try {
if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) {
socket.close();
}
} catch (error) {
console.error("safeCloseWebSocket error", error);
}
}
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 256).toString(16).slice(1));
}
function unsafeStringify(arr, offset = 0) {
return (
byteToHex[arr[offset + 0]] +
byteToHex[arr[offset + 1]] +
byteToHex[arr[offset + 2]] +
byteToHex[arr[offset + 3]] +
"-" +
byteToHex[arr[offset + 4]] +
byteToHex[arr[offset + 5]] +
"-" +
byteToHex[arr[offset + 6]] +
byteToHex[arr[offset + 7]] +
"-" +
byteToHex[arr[offset + 8]] +
byteToHex[arr[offset + 9]] +
"-" +
byteToHex[arr[offset + 10]] +
byteToHex[arr[offset + 11]] +
byteToHex[arr[offset + 12]] +
byteToHex[arr[offset + 13]] +
byteToHex[arr[offset + 14]] +
byteToHex[arr[offset + 15]]
).toLowerCase();
}
function stringify(arr, offset = 0) {
const uuid = unsafeStringify(arr, offset);
if (!isValidUUID(uuid)) {
throw TypeError("Stringified UUID is invalid");
}
return uuid;
}
/**
*
* @param {import("@cloudflare/workers-types").WebSocket} webSocket
* @param {ArrayBuffer} vlessResponseHeader
* @param {(string)=> void} log
*/
async function handleUDPOutBound(webSocket, vlessResponseHeader, log) {
let isVlessHeaderSent = false;
const transformStream = new TransformStream({
start(controller) {},
transform(chunk, controller) {
// udp message 2 byte is the the length of udp data
// TODO: this should have bug, beacsue maybe udp chunk can be in two websocket message
for (let index = 0; index < chunk.byteLength; ) {
const lengthBuffer = chunk.slice(index, index + 2);
const udpPakcetLength = new DataView(lengthBuffer).getUint16(0);
const udpData = new Uint8Array(chunk.slice(index + 2, index + 2 + udpPakcetLength));
index = index + 2 + udpPakcetLength;
controller.enqueue(udpData);
}
},
flush(controller) {},
});
// only handle dns udp for now
transformStream.readable
.pipeTo(
new WritableStream({
async write(chunk) {
const resp = await fetch(
dohURL, // dns server url
{
method: "POST",
headers: {
"content-type": "application/dns-message",
},
body: chunk,
}
);
const dnsQueryResult = await resp.arrayBuffer();
const udpSize = dnsQueryResult.byteLength;
// console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16)));
const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]);
if (webSocket.readyState === WS_READY_STATE_OPEN) {
log(`doh success and dns message length is ${udpSize}`);
if (isVlessHeaderSent) {
webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer());
} else {
webSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer());
isVlessHeaderSent = true;
}
}
},
})
)
.catch((error) => {
log("dns udp has error" + error);
});
const writer = transformStream.writable.getWriter();
return {
/**
*
* @param {Uint8Array} chunk
*/
write(chunk) {
writer.write(chunk);
},
};
}
function gettyConfig(userID, hostName) {
const vlessshare = btoa(`vless://${userID}@${IP1}:${PT1}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V1_${IP1}_${PT1}\nvless://${userID}@${IP2}:${PT2}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V2_${IP2}_${PT2}\nvless://${userID}@${IP3}:${PT3}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V3_${IP3}_${PT3}\nvless://${userID}@${IP4}:${PT4}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V4_${IP4}_${PT4}\nvless://${userID}@${IP5}:${PT5}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V5_${IP5}_${PT5}\nvless://${userID}@${IP6}:${PT6}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V6_${IP6}_${PT6}\nvless://${userID}@${IP7}:${PT7}?encryption=none&security=none&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V7_${IP7}_${PT7}\nvless://${userID}@${IP8}:${PT8}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V8_${IP8}_${PT8}\nvless://${userID}@${IP9}:${PT9}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V9_${IP9}_${PT9}\nvless://${userID}@${IP10}:${PT10}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V10_${IP10}_${PT10}\nvless://${userID}@${IP11}:${PT11}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V11_${IP11}_${PT11}\nvless://${userID}@${IP12}:${PT12}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V12_${IP12}_${PT12}\nvless://${userID}@${IP13}:${PT13}?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2560#CF_V13_${IP13}_${PT13}`);
return `${vlessshare}`
}
function getclConfig(userID, hostName) {
return `
proxies:
- name: CF_V1_${IP1}_${PT1}
type: vless
server: ${IP1}
port: ${PT1}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/worker34"
headers:
Host: ${hostName}
- name: CF_V2_${IP2}_${PT2}
type: vless
server: ${IP2}
port: ${PT2}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/worker3"
headers:
Host: ${hostName}
- name: CF_V3_${IP3}_${PT3}
type: vless
server: ${IP3}
port: ${PT3}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/wosa"
headers:
Host: ${hostName}
- name: CF_V4_${IP4}_${PT4}
type: vless
server: ${IP4}
port: ${PT4}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/finance"
headers:
Host: ${hostName}
- name: CF_V5_${IP5}_${PT5}
type: vless
server: ${IP5}
port: ${PT5}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/finance"
headers:
Host: ${hostName}
- name: CF_V6_${IP6}_${PT6}
type: vless
server: ${IP6}
port: ${PT6}
uuid: ${userID}
udp: false
tls: false
network: ws
ws-opts:
path: "/city"
headers:
Host: ${hostName}
- name: CF_V7_${IP7}_${PT7}
type: vless
server: ${IP7}
port: ${PT7}
uuid: ${userID}
udp: false
tls: false
network: ws
servername: ${hostName}
ws-opts:
path: "/city"
headers:
Host: ${hostName}
- name: CF_V8_${IP8}_${PT8}
type: vless
server: ${IP8}
port: ${PT8}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/cccc"
headers:
Host: ${hostName}
- name: CF_V9_${IP9}_${PT9}
type: vless
server: ${IP9}
port: ${PT9}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/thank_you"
headers:
Host: ${hostName}
- name: CF_V10_${IP10}_${PT10}
type: vless
server: ${IP10}
port: ${PT10}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/weather"
headers:
Host: ${hostName}
- name: CF_V11_${IP11}_${PT11}
type: vless
server: ${IP11}
port: ${PT11}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/weather"
headers:
Host: ${hostName}
- name: CF_V12_${IP12}_${PT12}
type: vless
server: ${IP12}
port: ${PT12}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/weather"
headers:
Host: ${hostName}
- name: CF_V13_${IP13}_${PT13}
type: vless
server: ${IP13}
port: ${PT13}
uuid: ${userID}
udp: false
tls: true
network: ws
servername: ${hostName}
ws-opts:
path: "/weather"
headers:
Host: ${hostName}
proxy-groups:
- name: 负载均衡
type: load-balance
url: http://www.gstatic.com/generate_204
interval: 300
proxies:
- CF_V1_${IP1}_${PT1}
- CF_V2_${IP2}_${PT2}
- CF_V3_${IP3}_${PT3}
- CF_V4_${IP4}_${PT4}
- CF_V5_${IP5}_${PT5}
- CF_V6_${IP6}_${PT6}
- CF_V7_${IP7}_${PT7}
- CF_V8_${IP8}_${PT8}
- CF_V9_${IP9}_${PT9}
- CF_V10_${IP10}_${PT10}
- CF_V11_${IP11}_${PT11}
- CF_V12_${IP12}_${PT12}
- CF_V13_${IP13}_${PT13}
- name: 自动选择
type: url-test
url: http://www.gstatic.com/generate_204
interval: 300
tolerance: 50
proxies:
- CF_V1_${IP1}_${PT1}
- CF_V2_${IP2}_${PT2}
- CF_V3_${IP3}_${PT3}
- CF_V4_${IP4}_${PT4}
- CF_V5_${IP5}_${PT5}
- CF_V6_${IP6}_${PT6}
- CF_V7_${IP7}_${PT7}
- CF_V8_${IP8}_${PT8}
- CF_V9_${IP9}_${PT9}
- CF_V10_${IP10}_${PT10}
- CF_V11_${IP11}_${PT11}
- CF_V12_${IP12}_${PT12}
- CF_V13_${IP13}_${PT13}
- name: 🌍选择代理
type: select
proxies:
- 负载均衡
- 自动选择
- DIRECT
- CF_V1_${IP1}_${PT1}
- CF_V2_${IP2}_${PT2}
- CF_V3_${IP3}_${PT3}
- CF_V4_${IP4}_${PT4}
- CF_V5_${IP5}_${PT5}
- CF_V6_${IP6}_${PT6}
- CF_V7_${IP7}_${PT7}
- CF_V8_${IP8}_${PT8}
- CF_V9_${IP9}_${PT9}
- CF_V10_${IP10}_${PT10}
- CF_V11_${IP11}_${PT11}
- CF_V12_${IP12}_${PT12}
- CF_V13_${IP13}_${PT13}
rules:
- GEOIP,LAN,DIRECT
- GEOIP,CN,DIRECT
- MATCH,🌍选择代理`
}

View File

@@ -0,0 +1,581 @@
/**
*
* @param {import("@cloudflare/workers-types").Request} request
*/
async function vlessOverWSHandler(request) {
/** @type {import("@cloudflare/workers-types").WebSocket[]} */
// @ts-ignore
const webSocketPair = new WebSocketPair();
const [client, webSocket] = Object.values(webSocketPair);
webSocket.accept();
let address = "";
let portWithRandomLog = "";
const log = (/** @type {string} */ info, /** @type {string | undefined} */ event) => {
console.log(`[${address}:${portWithRandomLog}] ${info}`, event || "");
};
const earlyDataHeader = request.headers.get("sec-websocket-protocol") || "";
const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log);
/** @type {{ value: import("@cloudflare/workers-types").Socket | null}}*/
let remoteSocketWapper = {
value: null,
};
let udpStreamWrite = null;
let isDns = false;
// ws --> remote
readableWebSocketStream
.pipeTo(
new WritableStream({
async write(chunk, controller) {
if (isDns && udpStreamWrite) {
return udpStreamWrite(chunk);
}
if (remoteSocketWapper.value) {
const writer = remoteSocketWapper.value.writable.getWriter();
await writer.write(chunk);
writer.releaseLock();
return;
}
const {
hasError,
message,
portRemote = 443,
addressRemote = "",
rawDataIndex,
vlessVersion = new Uint8Array([0, 0]),
isUDP,
} = await processVlessHeader(chunk, userID);
address = addressRemote;
portWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? "udp " : "tcp "} `;
if (hasError) {
// controller.error(message);
throw new Error(message); // cf seems has bug, controller.error will not end stream
// webSocket.close(1000, message);
return;
}
// if UDP but port not DNS port, close it
if (isUDP) {
if (portRemote === 53) {
isDns = true;
} else {
// controller.error('UDP proxy only enable for DNS which is port 53');
throw new Error("UDP proxy only enable for DNS which is port 53"); // cf seems has bug, controller.error will not end stream
return;
}
}
// ["version", "附加信息长度 N"]
const vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]);
const rawClientData = chunk.slice(rawDataIndex);
// TODO: support udp here when cf runtime has udp support
if (isDns) {
const { write } = await handleUDPOutBound(webSocket, vlessResponseHeader, log);
udpStreamWrite = write;
udpStreamWrite(rawClientData);
return;
}
handleTCPOutBound(
remoteSocketWapper,
addressRemote,
portRemote,
rawClientData,
webSocket,
vlessResponseHeader,
log
);
},
close() {
log(`readableWebSocketStream is close`);
},
abort(reason) {
log(`readableWebSocketStream is abort`, JSON.stringify(reason));
},
})
)
.catch((err) => {
log("readableWebSocketStream pipeTo error", err);
});
return new Response(null, {
status: 101,
// @ts-ignore
webSocket: client,
});
}
/**
* Checks if a given UUID is present in the API response.
* @param {string} targetUuid The UUID to search for.
* @returns {Promise<boolean>} A Promise that resolves to true if the UUID is present in the API response, false otherwise.
*/
async function checkUuidInApiResponse(targetUuid) {
// Check if any of the environment variables are empty
try {
const apiResponse = await getApiResponse();
if (!apiResponse) {
return false;
}
const isUuidInResponse = apiResponse.users.some((user) => user.uuid === targetUuid);
return isUuidInResponse;
} catch (error) {
console.error("Error:", error);
return false;
}
}
/**
* Handles outbound TCP connections.
*
* @param {any} remoteSocket
* @param {string} addressRemote The remote address to connect to.
* @param {number} portRemote The remote port to connect to.
* @param {Uint8Array} rawClientData The raw client data to write.
* @param {import("@cloudflare/workers-types").WebSocket} webSocket The WebSocket to pass the remote socket to.
* @param {Uint8Array} vlessResponseHeader The vless response header.
* @param {function} log The logging function.
* @returns {Promise<void>} The remote socket.
*/
async function handleTCPOutBound(
remoteSocket,
addressRemote,
portRemote,
rawClientData,
webSocket,
vlessResponseHeader,
log
) {
async function connectAndWrite(address, port) {
if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address)) address = `${atob('d3d3Lg==')}${address}${atob('LnNzbGlwLmlv')}`;
/** @type {import("@cloudflare/workers-types").Socket} */
const tcpSocket = connect({
hostname: address,
port: port,
});
remoteSocket.value = tcpSocket;
log(`connected to ${address}:${port}`);
const writer = tcpSocket.writable.getWriter();
await writer.write(rawClientData); // first write, nomal is tls client hello
writer.releaseLock();
return tcpSocket;
}
// if the cf connect tcp socket have no incoming data, we retry to redirect ip
async function retry() {
const tcpSocket = await connectAndWrite(proxyIP || addressRemote, proxyPort || portRemote);
// no matter retry success or not, close websocket
tcpSocket.closed
.catch((error) => {
console.log("retry tcpSocket closed error", error);
})
.finally(() => {
safeCloseWebSocket(webSocket);
});
remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log);
}
const tcpSocket = await connectAndWrite(addressRemote, portRemote);
// when remoteSocket is ready, pass to websocket
// remote--> ws
remoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log);
}
/**
*
* @param {import("@cloudflare/workers-types").WebSocket} webSocketServer
* @param {string} earlyDataHeader for ws 0rtt
* @param {(info: string)=> void} log for ws 0rtt
*/
function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {
let readableStreamCancel = false;
const stream = new ReadableStream({
start(controller) {
webSocketServer.addEventListener("message", (event) => {
if (readableStreamCancel) {
return;
}
const message = event.data;
controller.enqueue(message);
});
// The event means that the client closed the client -> server stream.
// However, the server -> client stream is still open until you call close() on the server side.
// The WebSocket protocol says that a separate close message must be sent in each direction to fully close the socket.
webSocketServer.addEventListener("close", () => {
// client send close, need close server
// if stream is cancel, skip controller.close
safeCloseWebSocket(webSocketServer);
if (readableStreamCancel) {
return;
}
controller.close();
});
webSocketServer.addEventListener("error", (err) => {
log("webSocketServer has error");
controller.error(err);
});
// for ws 0rtt
const { earlyData, error } = base64ToArrayBuffer(earlyDataHeader);
if (error) {
controller.error(error);
} else if (earlyData) {
controller.enqueue(earlyData);
}
},
pull(controller) {
// if ws can stop read if stream is full, we can implement backpressure
// https://streams.spec.whatwg.org/#example-rs-push-backpressure
},
cancel(reason) {
// 1. pipe WritableStream has error, this cancel will called, so ws handle server close into here
// 2. if readableStream is cancel, all controller.close/enqueue need skip,
// 3. but from testing controller.error still work even if readableStream is cancel
if (readableStreamCancel) {
return;
}
log(`ReadableStream was canceled, due to ${reason}`);
readableStreamCancel = true;
safeCloseWebSocket(webSocketServer);
},
});
return stream;
}
// https://xtls.github.io/development/protocols/vless.html
// https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw
/**
*
* @param { ArrayBuffer} vlessBuffer
* @param {string} userID
* @returns
*/
async function processVlessHeader(vlessBuffer, userID) {
if (vlessBuffer.byteLength < 24) {
return {
hasError: true,
message: "invalid data",
};
}
const version = new Uint8Array(vlessBuffer.slice(0, 1));
let isValidUser = false;
let isUDP = false;
const slicedBuffer = new Uint8Array(vlessBuffer.slice(1, 17));
const slicedBufferString = stringify(slicedBuffer);
const uuids = userID.includes(",") ? userID.split(",") : [userID];
const checkUuidInApi = await checkUuidInApiResponse(slicedBufferString);
isValidUser = uuids.some((userUuid) => checkUuidInApi || slicedBufferString === userUuid.trim());
console.log(`checkUuidInApi: ${await checkUuidInApiResponse(slicedBufferString)}, userID: ${slicedBufferString}`);
if (!isValidUser) {
return {
hasError: true,
message: "invalid user",
};
}
const optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0];
//skip opt for now
const command = new Uint8Array(vlessBuffer.slice(18 + optLength, 18 + optLength + 1))[0];
// 0x01 TCP
// 0x02 UDP
// 0x03 MUX
if (command === 1) {
} else if (command === 2) {
isUDP = true;
} else {
return {
hasError: true,
message: `command ${command} is not support, command 01-tcp,02-udp,03-mux`,
};
}
const portIndex = 18 + optLength + 1;
const portBuffer = vlessBuffer.slice(portIndex, portIndex + 2);
// port is big-Endian in raw data etc 80 == 0x005d
const portRemote = new DataView(portBuffer).getUint16(0);
let addressIndex = portIndex + 2;
const addressBuffer = new Uint8Array(vlessBuffer.slice(addressIndex, addressIndex + 1));
// 1--> ipv4 addressLength =4
// 2--> domain name addressLength=addressBuffer[1]
// 3--> ipv6 addressLength =16
const addressType = addressBuffer[0];
let addressLength = 0;
let addressValueIndex = addressIndex + 1;
let addressValue = "";
switch (addressType) {
case 1:
addressLength = 4;
addressValue = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)).join(".");
break;
case 2:
addressLength = new Uint8Array(vlessBuffer.slice(addressValueIndex, addressValueIndex + 1))[0];
addressValueIndex += 1;
addressValue = new TextDecoder().decode(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength));
break;
case 3:
addressLength = 16;
const dataView = new DataView(vlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength));
// 2001:0db8:85a3:0000:0000:8a2e:0370:7334
const ipv6 = [];
for (let i = 0; i < 8; i++) {
ipv6.push(dataView.getUint16(i * 2).toString(16));
}
addressValue = ipv6.join(":");
// seems no need add [] for ipv6
break;
default:
return {
hasError: true,
message: `invild addressType is ${addressType}`,
};
}
if (!addressValue) {
return {
hasError: true,
message: `addressValue is empty, addressType is ${addressType}`,
};
}
return {
hasError: false,
addressRemote: addressValue,
addressType,
portRemote,
rawDataIndex: addressValueIndex + addressLength,
vlessVersion: version,
isUDP,
};
}
/**
*
* @param {import("@cloudflare/workers-types").Socket} remoteSocket
* @param {import("@cloudflare/workers-types").WebSocket} webSocket
* @param {ArrayBuffer} vlessResponseHeader
* @param {(() => Promise<void>) | null} retry
* @param {*} log
*/
async function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) {
// remote--> ws
let remoteChunkCount = 0;
let chunks = [];
/** @type {ArrayBuffer | null} */
let vlessHeader = vlessResponseHeader;
let hasIncomingData = false; // check if remoteSocket has incoming data
await remoteSocket.readable
.pipeTo(
new WritableStream({
start() {},
/**
*
* @param {Uint8Array} chunk
* @param {*} controller
*/
async write(chunk, controller) {
hasIncomingData = true;
// remoteChunkCount++;
if (webSocket.readyState !== WS_READY_STATE_OPEN) {
controller.error("webSocket.readyState is not open, maybe close");
}
if (vlessHeader) {
webSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer());
vlessHeader = null;
} else {
// seems no need rate limit this, CF seems fix this??..
// if (remoteChunkCount > 20000) {
// // cf one package is 4096 byte(4kb), 4096 * 20000 = 80M
// await delay(1);
// }
webSocket.send(chunk);
}
},
close() {
log(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`);
// safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway.
},
abort(reason) {
console.error(`remoteConnection!.readable abort`, reason);
},
})
)
.catch((error) => {
console.error(`remoteSocketToWS has exception `, error.stack || error);
safeCloseWebSocket(webSocket);
});
// seems is cf connect socket have error,
// 1. Socket.closed will have error
// 2. Socket.readable will be close without any data coming
if (hasIncomingData === false && retry) {
log(`retry`);
retry();
}
}
/**
*
* @param {string} base64Str
* @returns
*/
function base64ToArrayBuffer(base64Str) {
if (!base64Str) {
return { error: null };
}
try {
// go use modified Base64 for URL rfc4648 which js atob not support
base64Str = base64Str.replace(/-/g, "+").replace(/_/g, "/");
const decode = atob(base64Str);
const arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0));
return { earlyData: arryBuffer.buffer, error: null };
} catch (error) {
return { error };
}
}
/**
* This is not real UUID validation
* @param {string} uuid
*/
function isValidUUID(uuid) {
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return uuidRegex.test(uuid);
}
const WS_READY_STATE_OPEN = 1;
const WS_READY_STATE_CLOSING = 2;
/**
* Normally, WebSocket will not has exceptions when close.
* @param {import("@cloudflare/workers-types").WebSocket} socket
*/
function safeCloseWebSocket(socket) {
try {
if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) {
socket.close();
}
} catch (error) {
console.error("safeCloseWebSocket error", error);
}
}
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 256).toString(16).slice(1));
}
function unsafeStringify(arr, offset = 0) {
return (
byteToHex[arr[offset + 0]] +
byteToHex[arr[offset + 1]] +
byteToHex[arr[offset + 2]] +
byteToHex[arr[offset + 3]] +
"-" +
byteToHex[arr[offset + 4]] +
byteToHex[arr[offset + 5]] +
"-" +
byteToHex[arr[offset + 6]] +
byteToHex[arr[offset + 7]] +
"-" +
byteToHex[arr[offset + 8]] +
byteToHex[arr[offset + 9]] +
"-" +
byteToHex[arr[offset + 10]] +
byteToHex[arr[offset + 11]] +
byteToHex[arr[offset + 12]] +
byteToHex[arr[offset + 13]] +
byteToHex[arr[offset + 14]] +
byteToHex[arr[offset + 15]]
).toLowerCase();
}
function stringify(arr, offset = 0) {
const uuid = unsafeStringify(arr, offset);
if (!isValidUUID(uuid)) {
throw TypeError("Stringified UUID is invalid");
}
return uuid;
}
/**
*
* @param {import("@cloudflare/workers-types").WebSocket} webSocket
* @param {ArrayBuffer} vlessResponseHeader
* @param {(string)=> void} log
*/
async function handleUDPOutBound(webSocket, vlessResponseHeader, log) {
let isVlessHeaderSent = false;
const transformStream = new TransformStream({
start(controller) {},
transform(chunk, controller) {
// udp message 2 byte is the the length of udp data
// TODO: this should have bug, beacsue maybe udp chunk can be in two websocket message
for (let index = 0; index < chunk.byteLength; ) {
const lengthBuffer = chunk.slice(index, index + 2);
const udpPakcetLength = new DataView(lengthBuffer).getUint16(0);
const udpData = new Uint8Array(chunk.slice(index + 2, index + 2 + udpPakcetLength));
index = index + 2 + udpPakcetLength;
controller.enqueue(udpData);
}
},
flush(controller) {},
});
// only handle dns udp for now
transformStream.readable
.pipeTo(
new WritableStream({
async write(chunk) {
const resp = await fetch(
dohURL, // dns server url
{
method: "POST",
headers: {
"content-type": "application/dns-message",
},
body: chunk,
}
);
const dnsQueryResult = await resp.arrayBuffer();
const udpSize = dnsQueryResult.byteLength;
// console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16)));
const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]);
if (webSocket.readyState === WS_READY_STATE_OPEN) {
log(`doh success and dns message length is ${udpSize}`);
if (isVlessHeaderSent) {
webSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer());
} else {
webSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer());
isVlessHeaderSent = true;
}
}
},
})
)
.catch((error) => {
log("dns udp has error" + error);
});
const writer = transformStream.writable.getWriter();
return {
/**
*
* @param {Uint8Array} chunk
*/
write(chunk) {
writer.write(chunk);
},
};
}

View File

@@ -0,0 +1,49 @@
核心运行逻辑、关键方法及函数的调用流程
核心运行逻辑
上述代码实现了一个 VLESS over WebSocket 代理服务器,主要功能是将客户端通过 WebSocket 发送的 VLESS 协议数据解析并转发到目标服务器,同时将目标服务器的响应数据回传给客户端。以下是其核心运行逻辑的步骤:
WebSocket 连接建立:
客户端发起 WebSocket 连接请求时vlessOverWSHandler 函数被触发。
创建一个 WebSocketPair包含客户端和服务器端的 WebSocket 对象,服务器端调用 accept() 接受连接。
从请求头中提取 sec-websocket-protocol 字段,用于处理可能的 Early Data0-RTT 数据)。
数据流转换:
使用 makeReadableWebSocketStream 函数将服务器端 WebSocket 的数据转换为 ReadableStream监听 WebSocket 的 message 事件,将接收到的数据推入流中。
当 WebSocket 关闭或出错时,流也会相应关闭或报错。
VLESS 协议解析与处理:
在 ReadableStream 的 write 方法中,处理客户端发送的数据块 (chunk)。
调用 processVlessHeader 解析 VLESS 协议头部提取目标地址、端口、协议类型TCP 或 UDP等信息。
根据解析结果:
如果是 UDP 请求且端口为 53DNS调用 handleUDPOutBound 处理 DNS 查询。
如果是 TCP 请求,调用 handleTCPOutBound 建立到目标服务器的连接并转发数据。
TCP 数据转发:
handleTCPOutBound 使用 connect 函数建立到目标服务器的 TCP 连接。
将客户端数据写入 TCP 连接,同时通过 remoteSocketToWS 将目标服务器的响应数据回传给 WebSocket 客户端。
UDPDNS数据转发
对于 DNS 请求handleUDPOutBound 将查询发送到指定的 DNS-over-HTTPS (DoH) 服务器,并将响应通过 WebSocket 回传给客户端。
关键方法及函数
以下是代码中关键的函数及其作用:
vlessOverWSHandler入口函数负责建立 WebSocket 连接并初始化数据流。
makeReadableWebSocketStream将 WebSocket 数据转换为 ReadableStream支持 Early Data 处理。
processVlessHeader解析 VLESS 协议头部,验证用户 UUID 并提取目标地址和端口。
handleTCPOutBound处理 TCP 请求,建立到目标服务器的连接并转发数据。
remoteSocketToWS将目标服务器的响应数据回传给 WebSocket 客户端。
handleUDPOutBound处理 UDPDNS请求向 DoH 服务器发送查询并返回结果。
checkUuidInApiResponse通过 API 验证用户 UUID 的有效性。
调用流程
客户端发起 WebSocket 请求,触发 vlessOverWSHandler。
创建并接受 WebSocket 连接,获取 Early Data如果存在
调用 makeReadableWebSocketStream 创建 ReadableStream监听 WebSocket 数据。
在 ReadableStream 的 write 方法中:
调用 processVlessHeader 解析数据。
如果是 DNS 请求UDP 端口 53调用 handleUDPOutBound。
如果是 TCP 请求,调用 handleTCPOutBound。
handleTCPOutBound
使用 connectAndWrite 建立 TCP 连接并写入客户端数据。
调用 remoteSocketToWS 将响应数据回传。
remoteSocketToWS
监听 TCP 连接的响应数据。
通过 WebSocket 发送给客户端。
handleUDPOutBoundDNS 请求):
发送 DNS 查询到 DoH 服务器。
将响应通过 WebSocket 返回。

View File

@@ -0,0 +1,14 @@
https://github.com/cmliu/edgetunnel
使用的cf账号 icederce@gmail.com
使用的clouddns的账号 icederce@gmail.com
实际部署完成地址
https://pp.icederce.ip-ddns.com/9116e3c0-8f35-45a8-8124-8904593555c4

View File

@@ -0,0 +1,25 @@
https://blog.090227.xyz/p/iptableNewProxyIP/
# 在Seoul-adm64-01上运行上述的能力
2606:4700:4400::6812:25e4
# 日志
sudo ip6tables -t nat -I PREROUTING -p tcp --dport 27443 -j LOG --log-prefix "IP6-DNAT-PREROUTING: " --log-level 6
sudo ip6tables -t nat -A PREROUTING -p tcp --dport 27443 -j DNAT --to-destination "[2606:4700:4400::6812:25e4]:443"
sudo ip6tables -t nat -A POSTROUTING -p tcp -d 2606:4700:4400::6812:25e4 --dport 443 -j MASQUERADE
# 清除转发
sudo ip6tables -t nat -F
# 实际转发IP
2603:c022:8008:8923:88a0:5c7d:2bb6:6ed5
27443
# 查看日志
sudo tail -f /var/log/syslog | grep "IP6-DNAT-PREROUTING"

View File

@@ -0,0 +1,25 @@
{
"inbounds": [
{
"protocol": "socks",
"port": 28888,
"listen": "0.0.0.0",
"settings": {
"auth": "password",
"accounts": [
{
"user": "zeaslity",
"pass": "cd28a746-283e-47cc-88f7-bb43d7f6b53a"
}
],
"udp": true,
"userLevel": 0
}
}
],
"outbounds": [
{
"protocol": "freedom"
}
]
}

View File

@@ -9,22 +9,12 @@
"accounts": [ "accounts": [
{ {
"user": "zeaslity", "user": "zeaslity",
"pass": "lovemm.23" "pass": "cd28a746-283e-47cc-88f7-bb43d7f6b53a"
} }
], ],
"udp": true, "udp": true,
"userLevel": 0 "userLevel": 0
} }
},
{
"protocol": "socks",
"port": 58889,
"listen": "0.0.0.0",
"settings": {
"auth": "noauth",
"udp": true,
"userLevel": 0
}
} }
], ],
"dns": { "dns": {

View File

@@ -15,9 +15,10 @@ export DOMAIN_NAME=xx.p2.vl.s4.107421.xyz
# seoul-arm-01 # seoul-arm-01
export DOMAIN_NAME=dify.107421.xyz export DOMAIN_NAME=dify.107421.xyz
# seoul-arm-01
export DOMAIN_NAME=pan.107421.xyz
export CF_Token="y-OqT1Gan37vBUC1YaedmkKbsH6Kf84RH6Ve2b5x"
export CF_Token="oXJRP5XI8Zhipa_PtYtB_jy6qWL0I9BosrJEYE8p"
export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191" export CF_Account_ID="dfaadeb83406ef5ad35da02617af9191"
export CF_Zone_ID="511894a4f1357feb905e974e16241ebb" export CF_Zone_ID="511894a4f1357feb905e974e16241ebb"
@@ -28,4 +29,4 @@ acme.sh --install-cert -d ${DOMAIN_NAME} --ecc \
--fullchain-file /etc/nginx/conf.d/ssl_key/${DOMAIN_NAME}.cert.pem \ --fullchain-file /etc/nginx/conf.d/ssl_key/${DOMAIN_NAME}.cert.pem \
--reloadcmd "systemctl restart nginx --force" --reloadcmd "systemctl restart nginx --force"
acme.sh --renew -d xx.t2.ll.c0.107421.xyz --ecc acme.sh --renew -d ${DOMAIN_NAME}--ecc

View File

@@ -0,0 +1,30 @@
server {
listen 80;
server_name yourdomain.com;
# 强制将所有HTTP请求重定向到HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 其他SSL配置可选
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 处理所有URI
location / {
# 你的后端服务配置
proxy_pass http://your_backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -0,0 +1,49 @@
server {
listen 80;
server_name heshun-admin.doublecheer.com;
# 强制将所有HTTP请求重定向到HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name heshun-admin.doublecheer.com;
# SSL配置
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 其他SSL配置可选
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 处理所有URI
location / {
root /home/hs/web/platform;
index index.html index.htm;
try_files $uri $uri/ @router;
}
location /prod-api/ {
rewrite ^/prod-api/(.*) /$1 break;
#两个反斜杆
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:30700;
}
location /play-api/ {
rewrite ^/play-api/(.*) /$1 break;
#两个反斜杆
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:30720;
}
location @router {
rewrite ^.*$ /index.html last;
}
}

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = hk.jumptoserver.com:51820

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = de-dus2.jumptoserver.com:51820

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = de-01.jumptoserver.com:51820

View File

@@ -0,0 +1,12 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = sg-01.jumptoserver.com:51820
sg-pro.jumptoserver.com:51820

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = jpjp.jumptoserver.com:51820

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = us-la-pro.jumptoserver.com:51820

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = uk-02.jumptoserver.com:51820

View File

@@ -0,0 +1 @@
z

View File

@@ -0,0 +1,9 @@
[Interface]
PrivateKey = 2CAHWJu6+lHWf3teVHLuXoF4Vad6xknSY/qLWPvgoGY=
Address = 172.16.145.79/32
DNS = 10.8.8.8
[Peer]
PublicKey = 658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=
AllowedIPs = 0.0.0.0/0
Endpoint = kr.jumptoserver.com:51820

1
tmp.sh
View File

@@ -1 +1,2 @@
eyJhbGciOiJSUzI1NiIsImtpZCI6IjVlZWI3OWMwOTkxM2FjODg2YzBjNjFmZTNiYTgxMzg5ZWU3MGM4OTdiMTNjY2YzNDVhNTg0NzJiNTI1YjY4NDQifQ.eyJhdWQiOlsiZmVjZTdmZmM3YWY4ODQ5NDEwMDA5N2ZjNDBlMjA1Mjc0YzRlZDBiYzgxMWZmMzBkZTFjYTRmYjc0MDY2YmNkMCJdLCJlbWFpbCI6ImljZWRlcmNlQGdtYWlsLmNvbSIsImV4cCI6MTc0MzU1ODMyNCwiaWF0IjoxNzQzNTU4MjY0LCJuYmYiOjE3NDM1NTgyNjQsImlzcyI6Imh0dHBzOi8vaWNlZGVyY2UuY2xvdWRmbGFyZWFjY2Vzcy5jb20iLCJ0eXBlIjoiYXBwIiwiaWRlbnRpdHlfbm9uY2UiOiI1T290ZXRCbG9KMUJyYU51Iiwic3ViIjoiZTcyMmVkNzItOGY4ZC01MjAwLTk1YTYtM2RiNThmODZjNGU4Iiwid2FycCI6dHJ1ZSwiaXAiOiIxOTMuMjM5Ljg2LjMiLCJhY2NvdW50X2lkIjoiY2JhYWFkOGExN2JlZmRlNTE0YTZhYWNmNDM0YzdmODkiLCJpZGVudGl0eSI6eyJlbWFpbCI6ImljZWRlcmNlQGdtYWlsLmNvbSJ9LCJjb3VudHJ5IjoiSEsifQ.hJNg7nHfAOoLYxdafuVjmHoo1g_OH566dbZEwtJpjbew0v3VtlMv1jTXKx7Fl60xmsh21_wyIwf7dhQIWdWpvN69qll3dkUW5E9NZTjDmjKQFmLcSYAFUUdXhLNjcZG3_b90sJHUCoSjna452k8dxyhYaYkYn-sMLx-MCemT8qNI63sDKAJDFOoC498NLbOd5Awbx66j_ksi5uXMYedu9vHjYSMhnVVf43GtJDw197L4mnfdHi9BfzB1pGt7mFvrFG3tfMKZkGupWgpiY0y1tz1VR-O_ZxfJOr_vGIfutpmz2-5qVMn76rVApwJK8EksjdRxZ6BTMHJWu4He4pDbBw

View File

@@ -0,0 +1,10 @@
剑哥你好,关于雄安交流的工作,我做了一定的工作和理解
背景是雄安政策对于低空经济的支持还是相当大的详见PPT已经有竞品公司中国电信成立团队中国邮政的无人机快递中国通号的低空监视防护网等各家公司的进驻
关于工作的理解和安排,总结如下:
1. 低空经济政策顶规:我已请教何博,对于相关的工作内容有了一定的了解。
2. 市场扩展:雄安移动的资源力度,能否考虑构建北方的示范基地
3. 工作及个人安排:可以外驻交流,脱离目前工作的“舒适圈”。主体工作交由技术支撑交付团队完成
还望剑哥批评指正,一切服从组织安排。