mirror of
https://github.com/XIU2/CloudflareSpeedTest.git
synced 2026-03-11 17:35:57 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c14627725c | ||
|
|
6c599ed1a6 | ||
|
|
e236a24a0c | ||
|
|
fc5cd11867 | ||
|
|
e9699196ef |
48
README.md
48
README.md
@@ -58,12 +58,13 @@ mkdir CloudflareST
|
|||||||
cd CloudflareST
|
cd CloudflareST
|
||||||
|
|
||||||
# 下载 CloudflareST 压缩包(自行根据需求替换 URL 中 [版本号] 和 [文件名])
|
# 下载 CloudflareST 压缩包(自行根据需求替换 URL 中 [版本号] 和 [文件名])
|
||||||
wget -N https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.0/CloudflareST_linux_amd64.tar.gz
|
wget -N https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_amd64.tar.gz
|
||||||
# 如果你是在国内网络环境中下载,那么请使用下面这几个镜像加速之一:
|
# 如果你是在国内网络环境中下载,那么请使用下面这几个镜像加速之一:
|
||||||
# wget -N https://ghp.ci/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.0/CloudflareST_linux_amd64.tar.gz
|
# wget -N https://ghfast.top/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_arm64.tar.gz
|
||||||
# wget -N https://ghproxy.cc/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.0/CloudflareST_linux_amd64.tar.gz
|
# wget -N https://wget.la/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_arm64.tar.gz
|
||||||
# wget -N https://ghproxy.net/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.0/CloudflareST_linux_amd64.tar.gz
|
# wget -N https://ghproxy.net/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_arm64.tar.gz
|
||||||
# wget -N https://gh-proxy.com/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.0/CloudflareST_linux_amd64.tar.gz
|
# wget -N https://gh-proxy.com/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_arm64.tar.gz
|
||||||
|
# wget -N https://hk.gh-proxy.com/https://github.com/XIU2/CloudflareSpeedTest/releases/download/v2.3.1/CloudflareST_linux_arm64.tar.gz
|
||||||
# 如果下载失败的话,尝试删除 -N 参数(如果是为了更新,则记得提前删除旧压缩包 rm CloudflareST_linux_amd64.tar.gz )
|
# 如果下载失败的话,尝试删除 -N 参数(如果是为了更新,则记得提前删除旧压缩包 rm CloudflareST_linux_amd64.tar.gz )
|
||||||
|
|
||||||
# 解压(不需要删除旧文件,会直接覆盖,自行根据需求替换 文件名)
|
# 解压(不需要删除旧文件,会直接覆盖,自行根据需求替换 文件名)
|
||||||
@@ -163,17 +164,22 @@ https://github.com/XIU2/CloudflareSpeedTest
|
|||||||
指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口)
|
指定测速端口;延迟测速/下载测速时使用的端口;(默认 443 端口)
|
||||||
-url https://cf.xiu2.xyz/url
|
-url https://cf.xiu2.xyz/url
|
||||||
指定测速地址;延迟测速(HTTPing)/下载测速时使用的地址,默认地址不保证可用性,建议自建;
|
指定测速地址;延迟测速(HTTPing)/下载测速时使用的地址,默认地址不保证可用性,建议自建;
|
||||||
当下载测速时,软件会从 HTTP 响应头中获取该 IP 当前的机场地区码(支持 Cloudflare、AWS CloudFront)并显示出来。
|
当下载测速时,软件会从 HTTP 响应头中获取该 IP 当前地区码(支持 Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny 等 CDN)并显示出来。
|
||||||
|
|
||||||
-httping
|
-httping
|
||||||
切换测速模式;延迟测速模式改为 HTTP 协议,所用测试地址为 [-url] 参数;(默认 TCPing)
|
切换测速模式;延迟测速模式改为 HTTP 协议,所用测试地址为 [-url] 参数;(默认 TCPing)
|
||||||
当使用 HTTP 测速模式时,软件会从 HTTP 响应头中获取该 IP 当前的机场地区码(支持 Cloudflare、AWS CloudFront)并显示出来。
|
当使用 HTTP 测速模式时,软件会从 HTTP 响应头中获取该 IP 当前地区码(支持 Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny 等 CDN)并显示出来。
|
||||||
注意:HTTPing 本质上也算一种 网络扫描 行为,因此如果你在服务器上面运行,需要降低并发(-n),否则可能会被一些严格的商家暂停服务。
|
注意:HTTPing 本质上也算一种 网络扫描 行为,因此如果你在服务器上面运行,需要降低并发(-n),否则可能会被一些严格的商家暂停服务。
|
||||||
如果你遇到 HTTPing 首次测速可用 IP 数量正常,后续测速越来越少甚至直接为 0,但停一段时间后又恢复了的情况,那么也可能是被 运营商、Cloudflare CDN 认为你在网络扫描而 触发临时限制机制,因此才会过一会儿就恢复了,建议降低并发(-n)减少这种情况的发生。
|
如果你遇到 HTTPing 首次测速可用 IP 数量正常,后续测速越来越少甚至直接为 0,但停一段时间后又恢复了的情况,那么也可能是被 运营商、Cloudflare CDN 认为你在网络扫描而 触发临时限制机制,因此才会过一会儿就恢复了,建议降低并发(-n)减少这种情况的发生。
|
||||||
-httping-code 200
|
-httping-code 200
|
||||||
有效状态代码;HTTPing 延迟测速时网页返回的有效 HTTP 状态码,仅限一个;(默认 200 301 302)
|
有效状态代码;HTTPing 延迟测速时网页返回的有效 HTTP 状态码,仅限一个;(默认 200 301 302)
|
||||||
-cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
-cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
||||||
匹配指定地区;地区名为当地机场地区码,英文逗号分隔,支持小写,支持 Cloudflare、AWS CloudFront,仅 HTTPing 模式可用;(默认 所有地区)
|
匹配指定地区;IATA 机场地区码或国家/城市码,英文逗号分隔,大小写均可,仅 HTTPing 模式可用;(默认 所有地区)
|
||||||
|
支持 Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny 等 CDN
|
||||||
|
其中 Cloudflare、AWS CloudFront、Fastly 使用的是 IATA 三字机场地区码,如:HKG,LAX
|
||||||
|
其中 CDN77、Bunny 使用的是 二字国家/区域码,如:US,CN
|
||||||
|
其中 Gcore 使用的是 二字城市码,如:FR,AM
|
||||||
|
因此大家使用 -cfcolo 指定地区码时要根据不同的 CDN 来指定不同类型的地区码。
|
||||||
|
|
||||||
-tl 200
|
-tl 200
|
||||||
平均延迟上限;只输出低于指定平均延迟的 IP,各上下限条件可搭配使用;(默认 9999 ms)
|
平均延迟上限;只输出低于指定平均延迟的 IP,各上下限条件可搭配使用;(默认 9999 ms)
|
||||||
@@ -388,7 +394,7 @@ HTTP 协议适用于快速测试某域名指向某 IP 时是否可以访问,
|
|||||||
|
|
||||||
> 另外,本软件 HTTPing 仅获取**响应头(response headers)**,并不获取正文内容(即 URL 文件大小不影响 HTTPing 测试,但如果你还要下载测速的话,那么还是需要一个大文件的),类似于 curl -i 功能。
|
> 另外,本软件 HTTPing 仅获取**响应头(response headers)**,并不获取正文内容(即 URL 文件大小不影响 HTTPing 测试,但如果你还要下载测速的话,那么还是需要一个大文件的),类似于 curl -i 功能。
|
||||||
|
|
||||||
> 另外,HTTPing 过程中,软件会从 HTTP 响应头中获取该 IP 当前的机场地区码(支持 Cloudflare、AWS CloudFront)并显示出来,而 TCPing 过程中无法这样做(但 下载测速 时也会这样做来获取地区码,毕竟下载测速也是个 HTTP 链接)
|
> 另外,HTTPing 过程中,软件会从 HTTP 响应头中获取该 IP 当前地区码(支持 Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny 等 CDN)并显示出来,而 TCPing 过程中无法这样做(但 下载测速 时也会这样做来获取地区码,毕竟下载测速也是个 HTTP 链接)
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
# 只需加上 -httping 参数即可切换到 HTTP 协议延迟测速模式
|
# 只需加上 -httping 参数即可切换到 HTTP 协议延迟测速模式
|
||||||
@@ -410,7 +416,7 @@ CloudflareST.exe -httping -tp 80 -url http://cdn.cloudflare.steamstatic.com/stea
|
|||||||
|
|
||||||
****
|
****
|
||||||
|
|
||||||
#### \# 匹配指定地区(colo 机场地区码)
|
#### \# 匹配指定地区
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><code><strong>「 点击展开 查看内容 」</strong></code></summary>
|
<summary><code><strong>「 点击展开 查看内容 」</strong></code></summary>
|
||||||
@@ -427,24 +433,32 @@ Cloudflare CDN 的节点 IP 是 Anycast IP,即每个 IP 对应的服务器节
|
|||||||
|
|
||||||
因此,对于这种 Anycast IP 的实际服务器位置,就不能靠那些在线 IP 地址位置查询网站来判断了。
|
因此,对于这种 Anycast IP 的实际服务器位置,就不能靠那些在线 IP 地址位置查询网站来判断了。
|
||||||
|
|
||||||
除了通过 **HTTP 响应头**获取机场地区码外(该功能的实现方式),还可以手动访问 `http://CloudflareIP/cdn-cgi/trace` 来获知 CDN 分配给你的实际节点地区机场地区码。
|
除了通过 **HTTP 响应头**获取地区码外(该功能的实现方式),还可以手动访问 `http://CloudflareIP/cdn-cgi/trace` 来获知 CDN 分配给你的实际节点地区码。
|
||||||
|
|
||||||
> 该功能支持 Cloudflare CDN 和 AWS CloudFront CDN,且这两个 CDN 的机场地区码是通用的(算是惯例)。
|
> 该功能支持 **Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny** 等 CDN。
|
||||||
> **注意**:如果你要用于筛选 AWS CloudFront CDN 地区,那么要通过 `-url` 参数指定一个使用 AWS CloudFront CDN 的下载测速地址(因为软件默认下载测速地址是 Cloudflare CDN 的)
|
> 但注意,不是所有 CDN 都支持 Anycast 技术的,很多 CDN 会限制一个网站能使用的 IP 范围。
|
||||||
|
|
||||||
|
> 其中 **Cloudflare、AWS CloudFront、Fastly** 都使用的是 **`IATA 三字机场地区码`**,如:HKG,LAX
|
||||||
|
> 而 **CDN77、Bunny** 使用的是 **`二字国家/区域码`**,如:US,CN
|
||||||
|
> **Gcore** 则使用的是 **`二字城市码`**,如:FR,AM
|
||||||
|
> 因此大家使用 `-cfcolo` 指定地区码时要根据不同的 CDN 来指定不同类型的地区码。
|
||||||
|
|
||||||
|
> **注意**:如果你要用于筛选 AWS CloudFront CDN 地区,那么要通过 `-url` 参数指定一个使用 AWS CloudFront CDN 的下载测速地址(因为软件默认下载测速地址是 Cloudflare CDN 的),另外有时候 HTTPing 模式测速一些 AWS CloudFront 地址会返回 403 错误,这种情况下需要加上 `-httping-code 403` 才能正确获取地区码。
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
# 指定地区名后,延迟测速后得到的结果就都是指定地区的 IP 了(如果没有指定 -dd 的话则会继续进行下载测速)
|
# 指定地区名后,延迟测速后得到的结果就都是指定地区的 IP 了(如果没有指定 -dd 的话则会继续进行下载测速)
|
||||||
# 如果延迟测速后结果为 0,则说明没有找到任何一个(未超时可用的)指定地区的 IP。
|
# 如果延迟测速后结果为 0,则说明没有找到任何一个(未超时可用的)指定地区的 IP。
|
||||||
# 节点地区名为当地 机场地区码,指定多个时用英文逗号分隔,v2.2.3 版本后支持小写
|
# 节点地区名为当地 IATA 机场地区码或国家/城市码,指定多个时用英文逗号分隔,v2.2.3 版本后支持小写
|
||||||
|
|
||||||
CloudflareST.exe -httping -cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
CloudflareST.exe -httping -cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
||||||
|
|
||||||
# 注意,该参数只有在 HTTPing 延迟测速模式下才可用(因为软件是通过 HTTP 链接中的响应头来获得该 IP 的实际地区机场地区码)
|
# 注意,该参数只有在 HTTPing 延迟测速模式下才可用(因为软件是通过 HTTP 链接中的响应头来获得该 IP 的实际地区码)
|
||||||
|
|
||||||
# 另外,HTTPing 过程中,软件会从 HTTP 响应头中获取该 IP 当前的机场地区码(支持 Cloudflare、AWS CloudFront)并显示出来,而 TCPing 过程中无法这样做(但 下载测速 时也会这样做来获取地区码,毕竟下载测速也是个 HTTP 链接)
|
# 另外,HTTPing 过程中,软件会从 HTTP 响应头中获取该 IP 当前地区码(支持 Cloudflare、AWS CloudFront、Fastly、Gcore、CDN77、Bunny 等 CDN)并显示出来,而 TCPing 过程中无法这样做(但 下载测速 时也会这样做来获取地区码,毕竟下载测速也是个 HTTP 链接)
|
||||||
```
|
```
|
||||||
|
|
||||||
> 两个 CDN 机场地区码通用,因此各地区名可见:https://www.cloudflarestatus.com/
|
> **`IATA 三字机场地区码`**,可见:https://www.cloudflarestatus.com/
|
||||||
|
> **`二字国家码`**,可见:[https://zh.wikipedia.org/wiki/ISO_3166-1二位字母代码#正式分配代码](https://zh.wikipedia.org/wiki/ISO_3166-1%E4%BA%8C%E4%BD%8D%E5%AD%97%E6%AF%8D%E4%BB%A3%E7%A0%81#%E6%AD%A3%E5%BC%8F%E5%88%86%E9%85%8D%E4%BB%A3%E7%A0%81)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -43,7 +43,7 @@ https://github.com/XIU2/CloudflareSpeedTest
|
|||||||
-httping-code 200
|
-httping-code 200
|
||||||
有效状态代码;HTTPing 延迟测速时网页返回的有效 HTTP 状态码,仅限一个;(默认 200 301 302)
|
有效状态代码;HTTPing 延迟测速时网页返回的有效 HTTP 状态码,仅限一个;(默认 200 301 302)
|
||||||
-cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
-cfcolo HKG,KHH,NRT,LAX,SEA,SJC,FRA,MAD
|
||||||
匹配指定地区;地区名为当地机场地区码,英文逗号分隔,仅 HTTPing 模式可用;(默认 所有地区)
|
匹配指定地区;IATA 机场地区码或国家/城市码,英文逗号分隔,仅 HTTPing 模式可用;(默认 所有地区)
|
||||||
|
|
||||||
-tl 200
|
-tl 200
|
||||||
平均延迟上限;只输出低于指定平均延迟的 IP,各上下限条件可搭配使用;(默认 9999 ms)
|
平均延迟上限;只输出低于指定平均延迟的 IP,各上下限条件可搭配使用;(默认 9999 ms)
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func downloadHandler(ip *net.IPAddr) (float64, string) {
|
|||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
if len(via) > 10 { // 限制最多重定向 10 次
|
if len(via) > 10 { // 限制最多重定向 10 次
|
||||||
if utils.Debug { // 调试模式下,输出更多信息
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
fmt.Printf("\033[31m[调试] IP: %s, 下载测速地址重定向次数过多,终止测速,URL: %s\033[0m\n", ip.String(), req.URL.String())
|
fmt.Printf("\033[31m[调试] IP: %s, 下载测速地址重定向次数过多,终止测速,下载测速地址: %s\033[0m\n", ip.String(), req.URL.String())
|
||||||
}
|
}
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ func downloadHandler(ip *net.IPAddr) (float64, string) {
|
|||||||
req, err := http.NewRequest("GET", URL, nil)
|
req, err := http.NewRequest("GET", URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if utils.Debug { // 调试模式下,输出更多信息
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
fmt.Printf("\033[31m[调试] IP: %s, 下载测速请求创建失败,错误信息: %v, URL: %s\033[0m\n", ip.String(), err, URL)
|
fmt.Printf("\033[31m[调试] IP: %s, 下载测速请求创建失败,错误信息: %v, 下载测速地址: %s\033[0m\n", ip.String(), err, URL)
|
||||||
}
|
}
|
||||||
return 0.0, ""
|
return 0.0, ""
|
||||||
}
|
}
|
||||||
@@ -141,18 +141,22 @@ func downloadHandler(ip *net.IPAddr) (float64, string) {
|
|||||||
response, err := client.Do(req)
|
response, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if utils.Debug { // 调试模式下,输出更多信息
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
fmt.Printf("\033[31m[调试] IP: %s, 下载测速失败,错误信息: %v, URL: , 最终URL: %s%s\033[0m\n", ip.String(), err, URL, response.Request.URL.String())
|
finalURL := URL // 默认的最终 URL,这样当 response 为空时也能输出
|
||||||
|
if response != nil && response.Request != nil && response.Request.URL != nil { // 如果 response 和 URL 存在,则获取最终 URL
|
||||||
|
finalURL = response.Request.URL.String()
|
||||||
|
}
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 下载测速失败,错误信息: %v, 下载测速地址: %s, 最终地址(如有重定向): %s\033[0m\n", ip.String(), err, URL, finalURL)
|
||||||
}
|
}
|
||||||
return 0.0, ""
|
return 0.0, ""
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
if response.StatusCode != 200 {
|
if response.StatusCode != 200 {
|
||||||
if utils.Debug { // 调试模式下,输出更多信息
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
fmt.Printf("\033[31m[调试] IP: %s, 下载测速终止,HTTP 状态码: %d, URL: %s, 最终URL: %s\033[0m\n", ip.String(), response.StatusCode, URL, response.Request.URL.String())
|
fmt.Printf("\033[31m[调试] IP: %s, 下载测速终止,HTTP 状态码: %d, 下载测速地址: %s, 最终地址(如有重定向): %s\033[0m\n", ip.String(), response.StatusCode, URL, response.Request.URL.String())
|
||||||
}
|
}
|
||||||
return 0.0, ""
|
return 0.0, ""
|
||||||
}
|
}
|
||||||
// 通过头部 Server 值判断是 Cloudflare 还是 AWS CloudFront 并设置 cfRay 为各自的机场地区码完整内容
|
// 通过头部参数获取地区码
|
||||||
colo := getHeaderColo(response.Header)
|
colo := getHeaderColo(response.Header)
|
||||||
|
|
||||||
timeStart := time.Now() // 开始时间(当前)
|
timeStart := time.Now() // 开始时间(当前)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package task
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
//"crypto/tls"
|
//"crypto/tls"
|
||||||
//"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@@ -11,14 +11,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/XIU2/CloudflareSpeedTest/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Httping bool
|
Httping bool
|
||||||
HttpingStatusCode int
|
HttpingStatusCode int
|
||||||
HttpingCFColo string
|
HttpingCFColo string
|
||||||
HttpingCFColomap *sync.Map
|
HttpingCFColomap *sync.Map
|
||||||
ColoRegexp = regexp.MustCompile(`[A-Z]{3}`)
|
RegexpColoIATACode = regexp.MustCompile(`[A-Z]{3}`) // 匹配 IATA 机场地区码(俗称 机场三字码)的正则表达式
|
||||||
|
RegexpColoCountryCode = regexp.MustCompile(`[A-Z]{2}`) // 匹配国家地区码的正则表达式(如 US、CN、UK 等)
|
||||||
|
RegexpColoGcore = regexp.MustCompile(`^[a-z]{2}`) // 匹配城市地区码的正则表达式(小写,如 us、cn、uk 等)
|
||||||
)
|
)
|
||||||
|
|
||||||
// pingReceived pingTotalTime
|
// pingReceived pingTotalTime
|
||||||
@@ -34,16 +38,22 @@ func (p *Ping) httping(ip *net.IPAddr) (int, time.Duration, string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 先访问一次获得 HTTP 状态码 及 Cloudflare Colo
|
// 先访问一次获得 HTTP 状态码 及 地区码
|
||||||
var colo string
|
var colo string
|
||||||
{
|
{
|
||||||
request, err := http.NewRequest(http.MethodHead, URL, nil)
|
request, err := http.NewRequest(http.MethodHead, URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 延迟测速请求创建失败,错误信息: %v, 测速地址: %s\033[0m\n", ip.String(), err, URL)
|
||||||
|
}
|
||||||
return 0, 0, ""
|
return 0, 0, ""
|
||||||
}
|
}
|
||||||
request.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36")
|
request.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36")
|
||||||
response, err := hc.Do(request)
|
response, err := hc.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 延迟测速失败,错误信息: %v, 测速地址: %s\033[0m\n", ip.String(), err, URL)
|
||||||
|
}
|
||||||
return 0, 0, ""
|
return 0, 0, ""
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
@@ -52,17 +62,23 @@ func (p *Ping) httping(ip *net.IPAddr) (int, time.Duration, string) {
|
|||||||
// 如果未指定的 HTTP 状态码,或指定的状态码不合规,则默认只认为 200、301、302 才算 HTTPing 通过
|
// 如果未指定的 HTTP 状态码,或指定的状态码不合规,则默认只认为 200、301、302 才算 HTTPing 通过
|
||||||
if HttpingStatusCode == 0 || HttpingStatusCode < 100 && HttpingStatusCode > 599 {
|
if HttpingStatusCode == 0 || HttpingStatusCode < 100 && HttpingStatusCode > 599 {
|
||||||
if response.StatusCode != 200 && response.StatusCode != 301 && response.StatusCode != 302 {
|
if response.StatusCode != 200 && response.StatusCode != 301 && response.StatusCode != 302 {
|
||||||
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 延迟测速终止,HTTP 状态码: %d, 测速地址: %s\033[0m\n", ip.String(), response.StatusCode, URL)
|
||||||
|
}
|
||||||
return 0, 0, ""
|
return 0, 0, ""
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if response.StatusCode != HttpingStatusCode {
|
if response.StatusCode != HttpingStatusCode {
|
||||||
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 延迟测速终止,HTTP 状态码: %d, 指定的 HTTP 状态码 %d, 测速地址: %s\033[0m\n", ip.String(), response.StatusCode, HttpingStatusCode, URL)
|
||||||
|
}
|
||||||
return 0, 0, ""
|
return 0, 0, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io.Copy(io.Discard, response.Body)
|
io.Copy(io.Discard, response.Body)
|
||||||
|
|
||||||
// 通过头部 Server 值判断是 Cloudflare 还是 AWS CloudFront 并设置 cfRay 为各自的机场地区码完整内容
|
// 通过头部参数获取地区码
|
||||||
colo = getHeaderColo(response.Header)
|
colo = getHeaderColo(response.Header)
|
||||||
|
|
||||||
// 只有指定了地区才匹配机场地区码
|
// 只有指定了地区才匹配机场地区码
|
||||||
@@ -70,6 +86,9 @@ func (p *Ping) httping(ip *net.IPAddr) (int, time.Duration, string) {
|
|||||||
// 判断是否匹配指定的地区码
|
// 判断是否匹配指定的地区码
|
||||||
colo = p.filterColo(colo)
|
colo = p.filterColo(colo)
|
||||||
if colo == "" { // 没有匹配到地区码或不符合指定地区则直接结束该 IP 测试
|
if colo == "" { // 没有匹配到地区码或不符合指定地区则直接结束该 IP 测试
|
||||||
|
if utils.Debug { // 调试模式下,输出更多信息
|
||||||
|
fmt.Printf("\033[31m[调试] IP: %s, 地区码不匹配: %s\033[0m\n", ip.String(), colo)
|
||||||
|
}
|
||||||
return 0, 0, ""
|
return 0, 0, ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,19 +137,57 @@ func MapColoMap() *sync.Map {
|
|||||||
|
|
||||||
// 从响应头中获取 地区码 值
|
// 从响应头中获取 地区码 值
|
||||||
func getHeaderColo(header http.Header) (colo string) {
|
func getHeaderColo(header http.Header) (colo string) {
|
||||||
// 如果是 Cloudflare 的服务器,则获取 CF-RAY 头部
|
if header.Get("server") != "" {
|
||||||
if header.Get("Server") == "cloudflare" {
|
// 如果是 Cloudflare CDN
|
||||||
colo = header.Get("CF-RAY") // 示例 cf-ray: 7bd32409eda7b020-SJC
|
// server: cloudflare
|
||||||
} else { // 如果是 AWS CloudFront 的服务器,则获取 X-Amz-Cf-Pop 头部
|
// cf-ray: 7bd32409eda7b020-SJC
|
||||||
colo = header.Get("x-amz-cf-pop") // 示例 X-Amz-Cf-Pop: SIN52-P1
|
if header.Get("server") == "cloudflare" {
|
||||||
|
if colo = header.Get("cf-ray"); colo != "" {
|
||||||
|
return RegexpColoIATACode.FindString(colo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是 CDN77 CDN(测试地址 https://www.cdn77.com
|
||||||
|
// server: CDN77-Turbo
|
||||||
|
// x-77-pop: losangelesUSCA // 美国的会显示为 USCA 不知道什么情况,暂时没做兼容,只提取 US
|
||||||
|
// x-77-pop: frankfurtDE
|
||||||
|
// x-77-pop: amsterdamNL
|
||||||
|
// x-77-pop: singaporeSG
|
||||||
|
if header.Get("server") == "CDN77-Turbo" {
|
||||||
|
if colo = header.Get("x-77-pop"); colo != "" {
|
||||||
|
return RegexpColoCountryCode.FindString(colo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是 Bunny CDN(测试地址 https://bunny.net
|
||||||
|
// server: BunnyCDN-TW1-1121
|
||||||
|
if colo = header.Get("server"); strings.Contains(colo, "BunnyCDN-") {
|
||||||
|
return RegexpColoCountryCode.FindString(strings.TrimPrefix(colo, "BunnyCDN-")) // 去掉 BunnyCDN- 前缀再去匹配
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果是 AWS CloudFront CDN(测试地址 https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips
|
||||||
|
// x-amz-cf-pop: SIN52-P1
|
||||||
|
if colo = header.Get("x-amz-cf-pop"); colo != "" {
|
||||||
|
return RegexpColoIATACode.FindString(colo)
|
||||||
|
}
|
||||||
|
// 如果是 Fastly CDN(测试地址 https://fastly.jsdelivr.net/gh/XIU2/CloudflareSpeedTest@master/go.mod
|
||||||
|
// x-served-by: cache-qpg1275-QPG
|
||||||
|
// x-served-by: cache-fra-etou8220141-FRA, cache-hhr-khhr2060043-HHR(最后一个为实际位置)
|
||||||
|
if colo = header.Get("x-served-by"); colo != "" {
|
||||||
|
if matches := RegexpColoIATACode.FindAllString(colo, -1); len(matches) > 0 {
|
||||||
|
return matches[len(matches)-1] // 因为 Fastly 的 x-served-by 可能包含多个地区码,所以只取最后一个
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Gcore CDN 的头部信息(注意均为城市代码而非国家代码),测试地址 https://assets.gcore.pro/assets/icons/shield-lock.svg
|
||||||
|
// x-id-fe: fr5-hw-edge-gc17
|
||||||
|
// x-shard: fr5-shard0-default
|
||||||
|
// x-id: fr5-hw-edge-gc28
|
||||||
|
if colo = header.Get("x-id-fe"); colo != "" {
|
||||||
|
if colo = RegexpColoGcore.FindString(colo); colo != "" {
|
||||||
|
return strings.ToUpper(colo) // 将小写的地区码转换为大写
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有获取到头部信息,说明不是 Cloudflare 和 AWS CloudFront,则直接返回空字符串
|
// 如果没有获取到头部信息,说明不是支持的 CDN,则直接返回空字符串
|
||||||
if colo == "" {
|
return ""
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// 正则匹配并返回 机场地区码
|
|
||||||
return ColoRegexp.FindString(colo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理地区码
|
// 处理地区码
|
||||||
|
|||||||
Reference in New Issue
Block a user