├── giffgaff.sh ├── README.md ├── _worker.js ├── ssh.sh └── tu.sh /giffgaff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 你的Telegram机器人API令牌和聊天ID 4 | API_TOKEN="xxxx" 5 | CHAT_ID="xxxxx" 6 | MESSAGE="giffgaff该续期啦!!!" 7 | 8 | # 向Telegram发送消息 9 | curl -s -X POST https://api.telegram.org/bot$API_TOKEN/sendMessage -d chat_id=$CHAT_ID -d text="$MESSAGE" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目略述 2 | * 对Colab某项目的重写,使代码能够部署在Cloudflare。 3 | * 很好的主(备)用节点,ip比较干净(能上GPT)。 4 | * `注意:本项目获取到的节点延迟低不一定代表速度快(节点的延迟随时发生很大的跳动),反过来也一样;如果发生能打开GPT但是上不了Youtube或者Google请换一个节点重试!!` 5 | 6 | * 已经修改成使用订阅转换器(三合一),在代码部分修改`WebToken: 'sub'//此处修改登录密码token`,默认( https://你的域名地址/sub )。 7 | 8 | # 部署教程 9 | * 测试项目与实际代码是不一样的,测试项目为了方便测试所以使用另一套代码写。 10 | * 将_worker.js里的代码直接复制到Cloudflare进行部署(或者fork之后pages部署`自行尝试`),默认Token为sub。 11 | * Pages部署诺要修改Token,增加变量名为`TOKEN`并自行修改,重新部署即可。 12 | * 代码部署到网页之后显示base64编码内容表示搭建成功,网页地址均为订阅链接(不需要复制网页内的base64编码导入软件)。 13 | * 代码已使用订阅转换器,可允许在Nekobox、V2ray、Clash、Singbox等软件进行订阅,其他软件可自行测试。 14 | * `注意:本项目一定要绑自定义域名,否则会获取不到节点信息!!` 15 | 16 | ## 项目测试 17 | * [测试地址](https://colad.xyhk.us.kg) 18 | 19 | ## 更多问题请联系: 20 | * [Telegram](https://t.me/Enkelte_bot) 21 | 22 | * [](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") 23 | -------------------------------------------------------------------------------- /_worker.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | WebToken: 'sub',//此处修改登录密码token 3 | FileName: 'Colab',MainData: '',urls: [],subconverter: "SUBAPI.fxxk.dedyn.io",subconfig: "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_MultiCountry.ini", subProtocol: 'https', 4 | }; 5 | export default { 6 | async fetch(request, env) { 7 | const userAgent = request.headers.get('User-Agent')?.toLowerCase() || "null"; 8 | const url = new URL(request.url); 9 | const token = url.searchParams.get('token'); 10 | config.WebToken = env.TOKEN || config.WebToken; 11 | config.subconverter = env.SUBAPI || config.subconverter; 12 | config.subconfig = env.SUBCONFIG || config.subconfig; 13 | config.FileName = env.SUBNAME || config.FileName; 14 | config.MainData = env.LINK || config.MainData; 15 | if (env.LINKSUB) config.urls = await addLinks(env.LINKSUB); 16 | await fetchAndDecryptData(); 17 | const currentDate = new Date(); 18 | currentDate.setHours(0, 0, 0, 0); 19 | const fakeToken = await MD5MD5(`${config.WebToken}${Math.ceil(currentDate.getTime() / 1000)}`); 20 | let allLinks = await addLinks(config.MainData + '\n' + config.urls.join('\n')); 21 | let selfHostedNodes = "", subscriptionLinks = ""; 22 | allLinks.forEach(x => x.toLowerCase().startsWith('http') ? subscriptionLinks += x + '\n' : selfHostedNodes += x + '\n'); 23 | config.MainData = selfHostedNodes; 24 | config.urls = await addLinks(subscriptionLinks); 25 | if (![config.WebToken, fakeToken].includes(token) && !url.pathname.includes("/" + config.WebToken)) { 26 | return new Response(await forbiddenPage(), { status: 200, headers: { 'Content-Type': 'text/html; charset=UTF-8' } }); 27 | } 28 | const subscriptionFormat = determineSubscriptionFormat(userAgent, url); 29 | let subscriptionConversionUrl = `${url.origin}/${await MD5MD5(fakeToken)}?token=${fakeToken}`; 30 | let req_data = config.MainData + (await getSubscription(config.urls, "v2rayn", request.headers.get('User-Agent')))[0].join('\n'); 31 | subscriptionConversionUrl += `|${(await getSubscription(config.urls, "v2rayn", request.headers.get('User-Agent')))[1]}`; 32 | if (env.WARP) subscriptionConversionUrl += `|${(await addLinks(env.WARP)).join("|")}`; 33 | const base64Data = btoa(req_data); 34 | if (subscriptionFormat === 'base64' || token === fakeToken) { 35 | return new Response(base64Data, { headers: { "content-type": "text/plain; charset=utf-8" } }); 36 | } 37 | try { 38 | const subconverterResponse = await fetch(buildSubconverterUrl(subscriptionFormat, subscriptionConversionUrl)); 39 | if (!subconverterResponse.ok) throw new Error(); 40 | let subconverterContent = await subconverterResponse.text(); 41 | if (subscriptionFormat === 'clash') subconverterContent = await clashFix(subconverterContent); 42 | return new Response(subconverterContent, { 43 | headers: { 44 | "Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(config.FileName)}; filename=${config.FileName}`, 45 | "content-type": "text/plain; charset=utf-8", 46 | }, 47 | }); 48 | } catch { 49 | return new Response(base64Data, { headers: { "content-type": "text/plain; charset=utf-8" } }); 50 | } 51 | } 52 | }; 53 | async function fetchAndDecryptData() { 54 | const apiUrl = 'https://web.enkelte.ggff.net/api/serverlist'; 55 | const headers = { 'accept': '/', 'appversion': '1.3.1', 'user-agent': 'SkrKK/1.3.1', 'content-type': 'application/x-www-form-urlencoded' }; 56 | const key = new TextEncoder().encode('65151f8d966bf596'); 57 | const iv = new TextEncoder().encode('88ca0f0ea1ecf975'); 58 | try { 59 | const encryptedData = await (await fetch(apiUrl, { headers })).text(); 60 | const decryptedData = await aes128cbcDecrypt(encryptedData, key, iv); 61 | const data = JSON.parse(decryptedData.match(/({.*})/)[0]).data; 62 | config.MainData = data.map(o => `ss://${btoa(`aes-256-cfb:${o.password}`)}@${o.ip}:${o.port}#${encodeURIComponent(o.title || '未命名')}`).join('\n'); 63 | } catch (error) { 64 | throw new Error('Error fetching or decrypting data: ' + error.message); 65 | } 66 | } 67 | function determineSubscriptionFormat(userAgent, url) { 68 | if (userAgent.includes('null') || userAgent.includes('subconverter')) return 'base64'; 69 | if (userAgent.includes('clash') || url.searchParams.has('clash')) return 'clash'; 70 | if (userAgent.includes('sing-box') || url.searchParams.has('sb') || url.searchParams.has('singbox')) return 'singbox'; 71 | if (userAgent.includes('surge') || url.searchParams.has('surge')) return 'surge'; 72 | return 'base64'; 73 | } 74 | function buildSubconverterUrl(subscriptionFormat, subscriptionConversionUrl) { 75 | return `${config.subProtocol}://${config.subconverter}/sub?target=${subscriptionFormat}&url=${encodeURIComponent(subscriptionConversionUrl)}&config=${encodeURIComponent(config.subconfig)}`; 76 | } 77 | async function addLinks(data) { 78 | return data.split("\n").filter(e => e.trim() !== ""); 79 | } 80 | async function getSubscription(urls, UA, userAgentHeader) { 81 | const headers = { "User-Agent": userAgentHeader || UA }; 82 | let subscriptionContent = [], unconvertedLinks = []; 83 | for (const url of urls) { 84 | try { 85 | const response = await fetch(url, { headers }); 86 | if (response.status === 200) { 87 | subscriptionContent.push((await response.text()).split("\n")); 88 | } else { 89 | unconvertedLinks.push(url); 90 | } 91 | } catch { 92 | unconvertedLinks.push(url); 93 | } 94 | } 95 | return [subscriptionContent.flat(), unconvertedLinks]; 96 | } 97 | async function clashFix(content) { 98 | return content.split("\n").reduce((acc, line) => { 99 | if (line.startsWith(" - name: ")) acc += ` - name: ${line.split("name: ")[1]}\n`; 100 | else acc += line + "\n"; 101 | return acc; 102 | }, ''); 103 | } 104 | async function forbiddenPage() { 105 | return `
Access Denied
`; 106 | } 107 | async function MD5MD5(value) { 108 | const encoded = new TextEncoder().encode(value); 109 | const buffer = await crypto.subtle.digest("MD5", await crypto.subtle.digest("MD5", encoded)); 110 | return Array.from(new Uint8Array(buffer)).map(b => b.toString(16).padStart(2, "0")).join(""); 111 | } 112 | async function aes128cbcDecrypt(encryptedText, key, iv) { 113 | const encryptedBuffer = hexStringToUint8Array(encryptedText); 114 | const algorithm = { name: 'AES-CBC', iv }; 115 | const keyObj = await crypto.subtle.importKey('raw', key, algorithm, false, ['decrypt']); 116 | try { 117 | const decryptedBuffer = await crypto.subtle.decrypt(algorithm, keyObj, encryptedBuffer); 118 | return new TextDecoder().decode(decryptedBuffer).replace(/\0+$/, ''); 119 | } catch { 120 | throw new Error('Decryption failed'); 121 | } 122 | } 123 | function hexStringToUint8Array(hexString) { 124 | return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); 125 | } 126 | 127 | -------------------------------------------------------------------------------- /ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | re="\033[0m" 4 | red="\033[1;91m" 5 | green="\e[1;32m" 6 | yellow="\e[1;33m" 7 | purple="\e[1;35m" 8 | red() { echo -e "\e[1;91m$1\033[0m"; } 9 | green() { echo -e "\e[1;32m$1\033[0m"; } 10 | yellow() { echo -e "\e[1;33m$1\033[0m"; } 11 | purple() { echo -e "\e[1;35m$1\033[0m"; } 12 | reading() { read -p "$(red "$1")" "$2"; } 13 | export LC_ALL=C 14 | USERNAME=$(whoami) 15 | HOSTNAME=$(hostname) 16 | export UUID=${UUID:-'dac0b07e-0923-41d0-8d00-e357b2ebec59'} 17 | export NEZHA_SERVER=${NEZHA_SERVER:-''} 18 | export NEZHA_PORT=${NEZHA_PORT:-'11112'} 19 | export NEZHA_KEY=${NEZHA_KEY:-''} 20 | export ARGO_DOMAIN=${ARGO_DOMAIN:-'gff.dpdns.org'} 21 | export ARGO_AUTH=${ARGO_AUTH:-'eyJhIjoiY2QExMTM4OTcwNDY0NDI2YjY1MWJjYTViYzkiLCJ0IjoiYTFhZGI5YTctYzM2My00NmM4LTk1MzEtMWYwZjhkYmM2OWZlIiwicyI6Ik5XTmpOemt6TTJZdFptUTNOQzAwT1dJM0xUZ3hOVEV0TkRCaE4yTXhOVFZoWkdabCJ9'} 22 | export VMESS_PORT=${VMESS_PORT:-'9443'} 23 | export TUIC_PORT=${TUIC_PORT:-'17250'} 24 | export HY2_PORT=${HY2_PORT:-'4475'} 25 | export CFIP=${CFIP:-'www.visa.com.sg'} 26 | export CFPORT=${CFPORT:-'443'} 27 | 28 | [[ "$HOSTNAME" == "s1.ct8.pl" ]] && WORKDIR="domains/${USERNAME}.ct8.pl/logs" || WORKDIR="domains/${USERNAME}.serv00.net/logs" 29 | [ -d "$WORKDIR" ] || (mkdir -p "$WORKDIR" && chmod 777 "$WORKDIR") 30 | bash -c 'ps aux | grep $(whoami) | grep -v "sshd\|bash\|grep" | awk "{print \$2}" | xargs -r kill -9 >/dev/null 2>&1' >/dev/null 2>&1 31 | # devil binexec on > /dev/null 2>&1 32 | 33 | argo_configure() { 34 | clear 35 | purple "正在安装中,请稍等..." 36 | if [[ -z $ARGO_AUTH || -z $ARGO_DOMAIN ]]; then 37 | green "ARGO_DOMAIN or ARGO_AUTH is empty,use quick tunnel" 38 | return 39 | fi 40 | 41 | if [[ $ARGO_AUTH =~ TunnelSecret ]]; then 42 | echo $ARGO_AUTH > tunnel.json 43 | cat > tunnel.yml << EOF 44 | tunnel: $(cut -d\" -f12 <<< "$ARGO_AUTH") 45 | credentials-file: tunnel.json 46 | protocol: http2 47 | 48 | ingress: 49 | - hostname: $ARGO_DOMAIN 50 | service: http://localhost:$VMESS_PORT 51 | originRequest: 52 | noTLSVerify: true 53 | - service: http_status:404 54 | EOF 55 | else 56 | green "ARGO_AUTH mismatch TunnelSecret,use token connect to tunnel" 57 | fi 58 | } 59 | 60 | generate_config() { 61 | 62 | openssl ecparam -genkey -name prime256v1 -out "private.key" 63 | openssl req -new -x509 -days 3650 -key "private.key" -out "cert.pem" -subj "/CN=$USERNAME.serv00.net" 64 | 65 | yellow "获取可用IP中,请稍等..." 66 | available_ip=$(get_ip) 67 | purple "当前选择IP为:$available_ip 如安装完后节点不通可尝试重新安装" 68 | 69 | cat > config.json << EOF 70 | { 71 | "log": { 72 | "disabled": true, 73 | "level": "info", 74 | "timestamp": true 75 | }, 76 | "dns": { 77 | "servers": [ 78 | { 79 | "address": "8.8.8.8", 80 | "address_resolver": "local" 81 | }, 82 | { 83 | "tag": "local", 84 | "address": "local" 85 | } 86 | ] 87 | }, 88 | "inbounds": [ 89 | { 90 | "tag": "hysteria-in", 91 | "type": "hysteria2", 92 | "listen": "$available_ip", 93 | "listen_port": $HY2_PORT, 94 | "users": [ 95 | { 96 | "password": "$UUID" 97 | } 98 | ], 99 | "masquerade": "https://bing.com", 100 | "tls": { 101 | "enabled": true, 102 | "alpn": [ 103 | "h3" 104 | ], 105 | "certificate_path": "cert.pem", 106 | "key_path": "private.key" 107 | } 108 | }, 109 | { 110 | "tag": "vmess-ws-in", 111 | "type": "vmess", 112 | "listen": "::", 113 | "listen_port": $VMESS_PORT, 114 | "users": [ 115 | { 116 | "uuid": "$UUID" 117 | } 118 | ], 119 | "transport": { 120 | "type": "ws", 121 | "path": "/vmess-argo", 122 | "early_data_header_name": "Sec-WebSocket-Protocol" 123 | } 124 | }, 125 | { 126 | "tag": "tuic-in", 127 | "type": "tuic", 128 | "listen": "$available_ip", 129 | "listen_port": $TUIC_PORT, 130 | "users": [ 131 | { 132 | "uuid": "$UUID", 133 | "password": "admin123" 134 | } 135 | ], 136 | "congestion_control": "bbr", 137 | "tls": { 138 | "enabled": true, 139 | "alpn": [ 140 | "h3" 141 | ], 142 | "certificate_path": "cert.pem", 143 | "key_path": "private.key" 144 | } 145 | } 146 | ], 147 | "outbounds": [ 148 | { 149 | "tag": "direct", 150 | "type": "direct" 151 | }, 152 | { 153 | "tag": "block", 154 | "type": "block" 155 | } 156 | ] 157 | } 158 | EOF 159 | } 160 | 161 | download_singbox() { 162 | ARCH=$(uname -m) && DOWNLOAD_DIR="." && mkdir -p "$DOWNLOAD_DIR" && FILE_INFO=() 163 | if [ "$ARCH" == "arm" ] || [ "$ARCH" == "arm64" ] || [ "$ARCH" == "aarch64" ]; then 164 | FILE_INFO=("https://github.com/eooce/test/releases/download/arm64/sb dape" "https://github.com/eooce/test/releases/download/arm64/bot13 bsos" "https://github.com/eooce/test/releases/download/ARM/swith ssho") 165 | elif [ "$ARCH" == "amd64" ] || [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "x86" ]; then 166 | FILE_INFO=("https://github.com/eooce/test/releases/download/freebsd/sb dape" "https://github.com/eooce/test/releases/download/freebsd/server bsos" "https://github.com/eooce/test/releases/download/freebsd/npm ssho") 167 | else 168 | echo "Unsupported architecture: $ARCH" 169 | exit 1 170 | fi 171 | declare -A FILE_MAP 172 | 173 | download_with_fallback() { 174 | local URL=$1 175 | local NEW_FILENAME=$2 176 | 177 | curl -L -sS --max-time 2 -o "$NEW_FILENAME" "$URL" & 178 | CURL_PID=$! 179 | CURL_START_SIZE=$(stat -c%s "$NEW_FILENAME" 2>/dev/null || echo 0) 180 | 181 | sleep 1 182 | CURL_CURRENT_SIZE=$(stat -c%s "$NEW_FILENAME" 2>/dev/null || echo 0) 183 | 184 | if [ "$CURL_CURRENT_SIZE" -le "$CURL_START_SIZE" ]; then 185 | kill $CURL_PID 2>/dev/null 186 | wait $CURL_PID 2>/dev/null 187 | wget -q -O "$NEW_FILENAME" "$URL" 188 | echo -e "\e[1;32mDownloading $NEW_FILENAME by wget\e[0m" 189 | else 190 | wait $CURL_PID 191 | echo -e "\e[1;32mDownloading $NEW_FILENAME by curl\e[0m" 192 | fi 193 | } 194 | 195 | # 固定文件名 196 | FILE_NAMES=("dape" "bsos" "ssho" "nezha-agent") 197 | 198 | for i in "${!FILE_INFO[@]}"; do 199 | URL=$(echo "${FILE_INFO[$i]}" | cut -d ' ' -f 1) 200 | NEW_FILENAME="$DOWNLOAD_DIR/${FILE_NAMES[$i]}" 201 | 202 | if [ -e "$NEW_FILENAME" ]; then 203 | echo -e "\e[1;32m$NEW_FILENAME already exists, Skipping download\e[0m" 204 | else 205 | download_with_fallback "$URL" "$NEW_FILENAME" 206 | fi 207 | 208 | chmod +x "$NEW_FILENAME" 209 | FILE_MAP[$(echo "${FILE_INFO[$i]}" | cut -d ' ' -f 2)]="$NEW_FILENAME" 210 | done 211 | wait 212 | 213 | if [ -e "$(basename ${FILE_MAP[ssho]})" ]; then 214 | tlsPorts=("443" "8443" "2096" "2087" "2083" "2053") 215 | if [[ "${tlsPorts[*]}" =~ "${NEZHA_PORT}" ]]; then 216 | NEZHA_TLS="--tls" 217 | else 218 | NEZHA_TLS="" 219 | fi 220 | if [ -n "$NEZHA_SERVER" ] && [ -n "$NEZHA_PORT" ] && [ -n "$NEZHA_KEY" ]; then 221 | export TMPDIR=$(pwd) 222 | nohup ./"$(basename ${FILE_MAP[ssho]})" -s ${NEZHA_SERVER}:${NEZHA_PORT} -p ${NEZHA_KEY} ${NEZHA_TLS} >/dev/null 2>&1 & 223 | sleep 2 224 | pgrep -x "$(basename ${FILE_MAP[ssho]})" > /dev/null && green "$(basename ${FILE_MAP[ssho]}) is running" || { red "$(basename ${FILE_MAP[ssho]}) is not running, restarting..."; pkill -x "$(basename ${FILE_MAP[ssho]})" && nohup ./"$(basename ${FILE_MAP[ssho]})" -s "${NEZHA_SERVER}:${NEZHA_PORT}" -p "${NEZHA_KEY}" ${NEZHA_TLS} >/dev/null 2>&1 & sleep 2; purple "$(basename ${FILE_MAP[ssho]}) restarted"; } 225 | else 226 | purple "NEZHA variable is empty, skipping running" 227 | fi 228 | fi 229 | 230 | if [ -e "$(basename ${FILE_MAP[dape]})" ]; then 231 | nohup ./"$(basename ${FILE_MAP[dape]})" run -c config.json >/dev/null 2>&1 & 232 | sleep 2 233 | pgrep -x "$(basename ${FILE_MAP[dape]})" > /dev/null && green "$(basename ${FILE_MAP[dape]}) is running" || { red "$(basename ${FILE_MAP[dape]}) is not running, restarting..."; pkill -x "$(basename ${FILE_MAP[dape]})" && nohup ./"$(basename ${FILE_MAP[dape]})" run -c config.json >/dev/null 2>&1 & sleep 2; purple "$(basename ${FILE_MAP[dape]}) restarted"; } 234 | fi 235 | 236 | if [ -e "$(basename ${FILE_MAP[bsos]})" ]; then 237 | if [[ $ARGO_AUTH =~ ^[A-Z0-9a-z=]{120,250}$ ]]; then 238 | args="tunnel --edge-ip-version auto --no-autoupdate --protocol http2 run --token ${ARGO_AUTH}" 239 | elif [[ $ARGO_AUTH =~ TunnelSecret ]]; then 240 | args="tunnel --edge-ip-version auto --config tunnel.yml run" 241 | else 242 | args="tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile boot.log --loglevel info --url http://localhost:$VMESS_PORT" 243 | fi 244 | nohup ./"$(basename ${FILE_MAP[bsos]})" $args >/dev/null 2>&1 & 245 | sleep 2 246 | pgrep -x "$(basename ${FILE_MAP[bsos]})" > /dev/null && green "$(basename ${FILE_MAP[bsos]}) is running" || { red "$(basename ${FILE_MAP[bsos]}) is not running, restarting..."; pkill -x "$(basename ${FILE_MAP[bsos]})" && nohup ./"$(basename ${FILE_MAP[bsos]})" "${args}" >/dev/null 2>&1 & sleep 2; purple "$(basename ${FILE_MAP[bsos]}) restarted"; } 247 | fi 248 | sleep 5 249 | rm -f "$(basename ${FILE_MAP[ssho]})" "$(basename ${FILE_MAP[dape]})" "$(basename ${FILE_MAP[bsos]})" 250 | } 251 | 252 | get_argodomain() { 253 | if [[ -n $ARGO_AUTH ]]; then 254 | echo "$ARGO_DOMAIN" 255 | else 256 | local retry=0 257 | local max_retries=6 258 | local argodomain="" 259 | while [[ $retry -lt $max_retries ]]; do 260 | ((retry++)) 261 | argodomain=$(grep -oE 'https://[[:alnum:]+\.-]+\.trycloudflare\.com' boot.log | sed 's@https://@@') 262 | if [[ -n $argodomain ]]; then 263 | break 264 | fi 265 | sleep 1 266 | done 267 | echo "$argodomain" 268 | fi 269 | } 270 | 271 | get_ip() { 272 | IP_LIST=($(devil vhost list | awk '/^[0-9]+/ {print $1}')) 273 | URL_TEMPLATE="https://www.toolsdaquan.com/toolapi/public/ipchecking" 274 | REFERER="https://www.toolsdaquan.com/ipcheck" 275 | IP="" 276 | THIRD_IP=${IP_LIST[2]} 277 | RESPONSE=$(curl -s --location --max-time 3 --request GET "${URL_TEMPLATE}/${THIRD_IP}/22" --header "Referer: ${REFERER}") 278 | if [[ $RESPONSE == '{"tcp":"success","icmp":"success"}' ]]; then 279 | IP=$THIRD_IP 280 | else 281 | FIRST_IP=${IP_LIST[0]} 282 | RESPONSE=$(curl -s --location --max-time 3 --request GET "${URL_TEMPLATE}/${FIRST_IP}/22" --header "Referer: ${REFERER}") 283 | 284 | if [[ $RESPONSE == '{"tcp":"success","icmp":"success"}' ]]; then 285 | IP=$FIRST_IP 286 | else 287 | IP=${IP_LIST[1]} 288 | fi 289 | fi 290 | echo "$IP" 291 | } 292 | 293 | get_links(){ 294 | argodomain=$(get_argodomain) 295 | echo -e "\e[1;32mArgoDomain:\e[1;35m${argodomain}\e[0m\n" 296 | ISP=$(curl -s --max-time 1.5 https://speed.cloudflare.com/meta | awk -F\" '{print $26}' | sed -e 's/ /_/g' || echo "0") 297 | get_name() { if [ "$HOSTNAME" = "s1.ct8.pl" ]; then SERVER="CT8"; else SERVER=$(echo "$HOSTNAME" | cut -d '.' -f 1); fi; echo "$SERVER"; } 298 | NAME="$ISP-$(get_name)" 299 | 300 | yellow "注意:v2ray或其他软件的跳过证书验证需设置为true,否则hy2或tuic节点可能不通\n" 301 | cat > list.txt <