diff --git a/CloudFlare.py b/CloudFlare.py new file mode 100644 index 0000000..1ad11cb --- /dev/null +++ b/CloudFlare.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# encoding:utf-8 + +import json +import math +import os +import platform +import re +import shutil +import subprocess +import sys +import time +from multiprocessing import Manager, Pool + +import requests + +original_host = [] + + +def main(): + cf_ips = get_cf_ips() + ping_test_dict = {} + ping_test_pool = {} + print('测试 ICMP 丢包率\n') + re_cmp = re.compile('(\d+\.\d+\.\d+\.\d+)[^\(]*\(\d+ avg, (\d+)\% loss\)', re.I) + r = check_icmp(cf_ips) + re_findall = re_cmp.findall(r) + for i in re_findall: + ping_test_dict[i[0]] = int(i[1]) + no_loss_ping = filter(lambda x: ping_test_dict[x] == 0, ping_test_dict) + no_loss_ping = list(no_loss_ping) + + if len(no_loss_ping) > 0: + print('测试完成,无丢包的 IP 总共有 {} 个,分别是:\n{}\n'.format(len(no_loss_ping), '\n'.join(no_loss_ping))) + check_speed(no_loss_ping) + else: + print('\n测试完成,选择 10 个丢包最低的 IP 进行速度测试\n') + ping_test_sorted = sorted(ping_test_dict.items(), key=lambda x: x[1]) + ping_test_cf_selected = [i[0] for i in ping_test_sorted[0:10]] + print('选择的 10 个丢包最低的 IP 分别是:\n{}\n'.format('\n'.join(ping_test_cf_selected))) + check_speed(ping_test_cf_selected) + + +def get_cf_ips(): + print('获取 CloudFlare 节点 IP 列表\n') + ret = requests.get('https://service.freecdn.workers.dev', timeout=30) + ret = ret.text.split('\n') + return ret[5:] + + +def check_icmp(ip): + re_cmp = re.compile('\(\d+ avg, (\d+)\% loss\)', re.I) + fping_list = [] + page_size = 600 + pages = int(math.ceil(len(ip) * 1.0 / page_size)) + page_list = range(1, pages + 1) + for i in page_list: + list_start = (i - 1) * page_size + list_end = i * page_size + ip_file = os.path.abspath(os.path.join(os.getcwd(), 'ip-{}.txt'.format(i))) + with open(ip_file, 'w') as f: + f.write('\n'.join(ip[list_start:list_end])) + cmd = 'fping -f {} -c 30 -i 1 -s 2>&1'.format(ip_file) + p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) + fping_list.append(p) + ping = '' + while True: + fping_end = [] + for p in fping_list: + if p.poll() is None: + r = p.stdout.readline() + r = r.decode('utf-8') + if re_cmp.findall(r): + ping += r + print(r.replace('\n', '')) + else: + fping_end.append(True) + if len(fping_end) == len(fping_list) and list(set(fping_end)) == [True]: + break + time.sleep(0.01) + for i in page_list: + ip_file = os.path.abspath(os.path.join(os.getcwd(), 'ip-{}.txt'.format(i))) + if os.path.exists(ip_file): + os.remove(ip_file) + return ping + + +def check_speed(ping_test_cf_selected): + print('开始对选中的 IP 进行速度测试...\n') + if os.path.exists(os.path.abspath(os.path.join(os.getcwd(), 'temp'))): + shutil.rmtree(os.path.abspath(os.path.join(os.getcwd(), 'temp'))) + os.makedirs(os.path.abspath(os.path.join(os.getcwd(), 'temp'))) + + for i in ping_test_cf_selected: + print('开始对 {} 进行速度测试'.format(i)) + cmd = 'curl --resolve speed.cloudflare.com:443:{0} https://speed.cloudflare.com/__down?bytes=1000000000 -o temp/{0} -s --connect-timeout 2 --max-time 10'.format( + i) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + while p.poll() is None: + time.sleep(0.1) + + print('\n测试完成,选择5个速度最快的 IP 进行源地址速度测试...\n') + speed_test_ips_list = [] + file_size_dict = {} + + for root, dirs, files in os.walk('temp'): + for i in files: + file_size_dict[i] = os.path.getsize(os.path.join('temp', i)) + + file_size_dict_sorted = sorted( + file_size_dict.items(), key=lambda x: x[1], reverse=True) + for i in range(5): + speed_test_ips_list.append(file_size_dict_sorted[i][0]) + print('选择的 5 个速度最快的 IP 分别是:\n{}'.format('\n'.join(speed_test_ips_list))) + for i in original_host: + check_speed_original(speed_test_ips_list, i) + + +def check_speed_original(speed_test_ips_list, original_address): + print('\n通过选中的 IP 开始对源地址 {} 进行速度测试...\n'.format(original_address)) + cf_speed_test_ips_dict = {} + for i in speed_test_ips_list: + print('开始对 {:15} 进行源地址速度测试'.format(i)) + if platform.system() == 'Windows': + cmd = 'curl --resolve {1}:443:{0} https://{1}/cf_speed_test -o nul --connect-timeout 5 --max-time 15'.format(i, original_address) + else: + cmd = 'curl --resolve {1}:443:{0} https://{1}/cf_speed_test -o /dev/null --connect-timeout 5 --max-time 15'.format(i, original_address) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + ret = '' + while p.poll() is None: + r = p.stdout.readline().decode('utf-8') + if r: + ret += r + time.sleep(0.01) + ret = ret.split('\n') + ret = ret[2] + ret = ret.split('\r') + ret = ret[-2] + while True: + if ' ' in ret: + ret = ret.replace(' ', ' ') + else: + break + ret = ret.split(' ') + ret = ret[7] + if 'M' in ret: + ret = '{}k'.format(float(ret.replace('M', '')) * 1024) + if 'k' in ret: + ret = float(ret.replace('k', '')) * 1024 + ret = float(ret) + cf_speed_test_ips_dict[i] = ret + print('\n源地址速度测试完成\n') + print('对 https://{}/cf_speed_test 进行的下载速度测试结果如下:\n'.format(original_address)) + cf_speed_test_ips_list = sorted(cf_speed_test_ips_dict.items(), key=lambda x: x[1], reverse=True) + for i in cf_speed_test_ips_list: + ret = 'IP {:15} Speed {:10}k'.format(i[0], round(i[1] * 1.0 / 1024, 2)) + print(ret) + + if os.path.exists(os.path.abspath(os.path.join(os.getcwd(), 'temp'))): + shutil.rmtree(os.path.abspath(os.path.join(os.getcwd(), 'temp'))) + + +if __name__ == '__main__': + original_host = input('请输入测试地址,如果有多个地址请以半角空格分割:') + original_host = original_host.split(' ') + if len(original_host) > 0: + start_time = time.time() + main() + print('累计测试时间: {} 秒'.format(int(time.time() - start_time))) + else: + print('输入错误!请重新运行此脚本!') \ No newline at end of file diff --git a/README.md b/README.md index 61194cb..7dae20a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,70 @@ -# better-cloudflare-ip -shell脚本,适合中国大陆用户查找适合自己当前网络环境的优选cloudflare anycast IP +## 感谢 + +本项目Fork自 badafans/better-cloudflare-ip + +感谢 badafans 提供 Cloudflare Anycast 节点汇总 + +## 使用申明 +本项目侧重于研究任播技术中丢包率与网速的相互关系,仅供学习使用 + +### 禁止使用范围准则如下 + +a) 相关机构提示网页有威胁的,有非法信息提示的网站。 + +b)医院类型网站(流产,皮肤病,性病等医院),未获得卫生部资质的网站。 + +c)网站主体内容含有色情(视频交友,一夜情交友)、违法(办假证,贩卖仿真枪)、封建迷信、游戏私服、游戏外挂、网赚、两性、美女贴图和动漫贴图(尺度过大)、赌博(含贩卖赌博工具。)、博彩等内容。 + +d)网站存在恶意流氓广告(存在非法内容视频链接,非法网页内容链接)。 + +e)网站存在任何破坏或试图破坏网络安全的行为,以病毒、木马、恶意代码、钓鱼等方式,试图对网站、网络相关软硬件进行恶意扫描、非法侵入系统、非法获取数据等内容。 + +f)网站内容存在版权风险的网站(视频,小说,音乐等网站)。 + +g)网站含有药品销售、保健品销售,但未取得资质的,或严重夸大药效事实。 + +h)网站主要业务为向非法网站提供支付、交易平台、担保,代理外国金融理财(炒股,炒现货,炒黄金)等服务的网站。 + +i)网站中大量存在影响社会和谐稳定的内容的网站(涉嫌攻击国家,攻击领导人,攻击人民,言论煽动性质网站)。 + +j)网站内容含有国家相关法律法规不允许的其他内容。 + +k)网站内容含有VPN,网络代理等内容。 + +l) 通过技术手段或非技术手段干扰Cloudflare所有产品正常运营的网站。 + +m)网站内容为发布虚假不实消息行为,或侵害了他人的合法权益行为的网站。 + +n) 获取网站内容需要通过登录等方式,无法直接查看造成内容无法审核的网站。 + +o) 提供影视、软件和应用等下载服务的网站。 + +## 介绍 + +* 用 Python3 重写了测试脚本; + +* 使用多线程优化 Ping 测试,大大缩短测试时间; + +* 不再设置测速阀值,而是择优选择数个 IP 进行速度测试; + +* 新增通过 anycast IP 进行原始服务器测速,获取真实下载速度; + +## 说明 + ++ 继续使用 badafans/better-cloudflare-ip 项目中的 curl 和 fping 工具 + ++ 需要安装 Python3 (Windows / Linux 通用) + ++ 通过 pip3 安装 requests + ++ 在原始服务器的网站根目录下生成测试文件 + + + dd if=/dev/zero of=cf_speed_test bs=1M count=100 + + + 要能以 https://(cf中分配或者解析的域名)/cf_speed_test 访问并下载 + + + 测试下载速度时将进行 15 秒的下载操作 + ++ 在脚本中配置 original_host 参数 + ++ 运行脚本进行测速 diff --git a/better-cloudflare-ip-win32.zip b/better-cloudflare-ip-win32.zip new file mode 100644 index 0000000..8f05924 Binary files /dev/null and b/better-cloudflare-ip-win32.zip differ diff --git a/cf.sh b/cf.sh new file mode 100644 index 0000000..20b1306 --- /dev/null +++ b/cf.sh @@ -0,0 +1,313 @@ +#!/bin/bash +# random cloudflare anycast ip +declare -i bandwidth +declare -i speed +read -p "请设置期望到 CloudFlare 服务器的带宽大小(单位 Mbps):" bandwidth +speed=bandwidth*128*1024 +starttime=`date +'%Y-%m-%d %H:%M:%S'` +while true +do + while true + do + declare -i n + declare -i per + declare -i count + rm -rf icmp temp log.txt data.txt anycast.txt + mkdir icmp + curl --ipv4 https://service.freecdn.workers.dev -# -o data.txt + publicip=$(cat data.txt | grep publicip: | cut -f 2- -d':') + domain=$(cat data.txt | grep domain: | cut -f 2- -d':') + file=$(cat data.txt | grep file: | cut -f 2- -d':') + url=$(cat data.txt | grep url: | cut -f 2- -d':') + version=$(cat data.txt | grep version: | cut -f 2- -d':') + if [ "$version" != "20201108" ] + then + echo 发现新版本: $version + echo 更新地址: $url + echo 更新后才可以使用 + exit + fi + n=0 + count=$(($RANDOM%5)) + for i in `cat data.txt | sed '1,5d'` + do + if [ $n -eq $count ] + then + echo $i>>anycast.txt + count+=4 + else + n+=1 + fi + done + rm -rf data.txt + n=0 + m=$(cat anycast.txt | wc -l) + count=m/30+1 + for i in `cat anycast.txt` + do + ping -c $count -i 0.2 -n -q $i > icmp/$n.log& + n=$[$n+1] + per=$n*100/$m + while true + do + p=$(ps -ef | grep ping | grep -v "grep" | wc -l) + if [ $p -ge 200 ] + then + echo 正在测试 ICMP 丢包率:进程数 $p,已完成 $per % + sleep 0.5 + else + echo 正在测试 ICMP 丢包率:进程数 $p,已完成 $per % + break + fi + done + done + rm -rf anycast.txt + while true + do + p=$(ps -ef | grep ping | grep -v "grep" | wc -l) + if [ $p -ne 0 ] + then + echo 等待 ICMP 进程结束:剩余进程数 $p + sleep 1 + else + echo ICMP 丢包率测试完成 + break + fi + done + cat icmp/*.log | sed -n '3~5p;4~5p' | sed -n '{N;s/\n/\t/p}' | cut -f 1 -d'%' | awk '{print $2,$NF}' | sort -k 2 -n | awk '{print $1}' | sed '31,$d' > ip.txt + rm -rf icmp + echo 选取30个丢包率最少的IP地址下载测速 + mkdir temp + for i in `cat ip.txt` + do + echo $i 启动测速 + curl --resolve $domain:443:$i https://$domain/$file -o temp/$i -s --connect-timeout 2 --max-time 10& + done + echo 等待测速进程结束,筛选出三个优选的IP + sleep 15 + echo 测速完成 + ls -S temp > ip.txt + rm -rf temp + n=$(wc -l ip.txt | awk '{print $1}') + if [ $n -ge 3 ]; then + first=$(sed -n '1p' ip.txt) + second=$(sed -n '2p' ip.txt) + third=$(sed -n '3p' ip.txt) + rm -rf ip.txt + echo 优选的IP地址为 $first - $second - $third + echo 第一次测试 $first + curl --resolve $domain:443:$first https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$first + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + echo 第二次测试 $first + curl --resolve $domain:443:$first https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$first + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + echo 第一次测试 $second + curl --resolve $domain:443:$second https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$second + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + echo 第二次测试 $second + curl --resolve $domain:443:$second https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$second + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + echo 第一次测试 $third + curl --resolve $domain:443:$third https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$third + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + echo 第二次测试 $third + curl --resolve $domain:443:$third https://$domain/$file -o /dev/null --connect-timeout 5 --max-time 10 > log.txt 2>&1 + cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep -v 'k\|M' >> speed.txt + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep k | sed 's/k//g'` + do + declare -i k + k=$i + k=k*1024 + echo $k >> speed.txt + done + for i in `cat log.txt | tr '\r' '\n' | awk '{print $NF}' | sed '1,3d;$d' | grep M | sed 's/M//g'` + do + i=$(echo | awk '{print '$i'*10 }') + declare -i M + M=$i + M=M*1024*1024/10 + echo $M >> speed.txt + done + declare -i max + max=0 + for i in `cat speed.txt` + do + max=$i + if [ $i -ge $max ]; then + max=$i + fi + done + rm -rf log.txt speed.txt + if [ $max -ge $speed ]; then + anycast=$third + break + fi + max=$[$max/1024] + echo 峰值速度 $max kB/s + fi + done + break +done + max=$[$max/1024] + endtime=`date +'%Y-%m-%d %H:%M:%S'` + start_seconds=$(date --date="$starttime" +%s) + end_seconds=$(date --date="$endtime" +%s) + clear + echo 优选IP $anycast 满足 $bandwidth Mbps带宽需求 + echo 峰值速度 $max kB/s + echo 出口IP $publicip 总计用时 $((end_seconds-start_seconds)) 秒 \ No newline at end of file diff --git a/curl.zip b/curl.zip new file mode 100644 index 0000000..f0e8702 Binary files /dev/null and b/curl.zip differ diff --git a/fping-4.2.tar.gz b/fping-4.2.tar.gz new file mode 100644 index 0000000..d0fc6fe Binary files /dev/null and b/fping-4.2.tar.gz differ