fix: 修复上游识别,支持直接导入basics识别到的IP地址,而不再重新获取IP地址减少等待时间

This commit is contained in:
spiritlhl
2025-08-05 09:28:26 +00:00
parent 3e6524fa0e
commit 1c2e9cdab9
9 changed files with 57 additions and 95 deletions

View File

@@ -61,7 +61,7 @@ Shell 版本:[https://github.com/spiritLHLS/ecs](https://github.com/spiritLHLS
- 常见流媒体测试并发查询:[UnlockTests](https://github.com/oneclickvirt/UnlockTests),逻辑借鉴 [RegionRestrictionCheck](https://github.com/lmc999/RegionRestrictionCheck) 等
- IP 质量/安全信息并发查询:二进制文件编译至 [securityCheck](https://github.com/oneclickvirt/securityCheck)
- 邮件端口测试:[portchecker](https://github.com/oneclickvirt/portchecker)
- 三网回程测试:借鉴 [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace),二次开发至 [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)
- 上游及回程路由线路检测:借鉴 [zhanghanyun/backtrace](https://github.com/zhanghanyun/backtrace),二次开发至 [oneclickvirt/backtrace](https://github.com/oneclickvirt/backtrace)
- 三网路由测试:基于 [NTrace-core](https://github.com/nxtrace/NTrace-core),二次开发至 [nt3](https://github.com/oneclickvirt/nt3)
- 网速测试:基于 [speedtest.net](https://github.com/spiritLHLS/speedtest.net-CN-ID) 和 [speedtest.cn](https://github.com/spiritLHLS/speedtest.cn-CN-ID) 数据,开发至 [oneclickvirt/speedtest](https://github.com/oneclickvirt/speedtest)
- 三网 Ping 值测试:借鉴 [ecsspeed](https://github.com/spiritLHLS/ecsspeed),二次开发至 [pingtest](https://github.com/oneclickvirt/pingtest)

View File

@@ -189,13 +189,37 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
### **上游及回程线路检测**
先是检测当前IP地址的BGP拓扑图展示直接/间接接入的上游有哪些,直接接入的好上游越多,一般来说连通性越好
#### 上游类型与运营商等级说明
区别什么上游好一般来说无法准确判断,因为除了```Tier1 Global```,其他接入都是需要给钱的,买的什么套餐对等口子多大这块可查不出来
- **直接上游Direct Upstream**
当前运营商直接购买网络服务的上级运营商,通常是 BGP 邻居。
- **间接上游Indirect Upstream**
直接上游的上级,形成层层向上的关系链。可通过 BGP 路由路径中的多跳信息识别。
| 等级 | 描述 |
|------|------|
| **Tier 1 Global** | 全球顶级运营商(如 AT&T、Verizon、NTT、Telia 等之间免费互联Settlement-Free Peering不依赖他人即可访问全球任意网络。 |
| **Tier 1 Regional** | 区域性顶级运营商,在特定区域具有一级能力,但在全球范围互联性稍弱。 |
| **Tier 1 Indirect** | 间接连接的 Tier 1非直接购买通过中间上游间接接入 Tier 1 网络。 |
| **Tier 2** | 需要向 Tier 1 付费购买上网能力的二级运营商,通常是各国主流电信商或 ISP。 |
| **CDN Provider** | 内容分发网络提供商,如 Cloudflare、Akamai、Fastly 等,主要用于内容加速而非传统上游。 |
| **Direct/Indirect Others** | 其他类型的直接或间接连接,如 IXInternet Exchange成员、私有对等互联等。 |
上游质量判断:直接接入的高等级上游(特别是 Tier 1 Global越多通常网络连通性越好。但实际网络质量也受到以下因素影响
- 上下游之间的商业结算关系;
- 购买的带宽套餐和服务质量;
- 对等端口Peering Ports大小和负载
- 网络拥塞、路由策略、延迟路径等。
无法完全从 BGP 路由中判断。
一般来说,**接入高质量上游越多,网络连通性越优**。但由于存在诸多不可见的商业和技术因素,**无法仅凭上游等级准确判断网络质量**上游检测约等于图一乐实际得看对应的路由情况和长时间Ping的情况。
然后是检测当前的宿主机的IP地址 到 四个主要POP点城市的三个主要运营商的接入点的IP地址 的线路,具体来说
电信163、联通4837、移动CMI 是常见的线路
电信163、联通4837、移动CMI 是常见的线路移动CMI对两广地区的移动运营商特供延迟低也能算优质仅限两广移动。
电信CN2GIA > 电信CN2GT 移动CMIN2 联通9929 算优质的线路
@@ -203,9 +227,9 @@ AMD的7950x单核满血性能得分在6500左右AMD的5950x单核满血性能
### **三网回程路由检测**
默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的说明。
默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的参数说明。
主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。
主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。有时候路由信息完全藏起来了,只知道实际使用的延迟低,实际可能也是优质线路只是查不到信息,这就没办法直接识别了。
### **就近测速**

6
go.mod
View File

@@ -6,8 +6,8 @@ require (
github.com/imroc/req/v3 v3.54.0
github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841
github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204
github.com/oneclickvirt/backtrace v0.0.6-20250801151556
github.com/oneclickvirt/basics v0.0.15-20250728021329
github.com/oneclickvirt/backtrace v0.0.6-20250805091811
github.com/oneclickvirt/basics v0.0.15-20250805084236
github.com/oneclickvirt/cputest v0.0.12-20250720122317
github.com/oneclickvirt/defaultset v0.0.2-20240624082446
github.com/oneclickvirt/disktest v0.0.9-20250801101625
@@ -16,7 +16,7 @@ require (
github.com/oneclickvirt/nt3 v0.0.6-20250726150925
github.com/oneclickvirt/pingtest v0.0.8-20250728015259
github.com/oneclickvirt/portchecker v0.0.3-20250728015900
github.com/oneclickvirt/security v0.0.6-20250727160145
github.com/oneclickvirt/security v0.0.6-20250805090112
github.com/oneclickvirt/speedtest v0.0.10-20250728015734
)

12
go.sum
View File

@@ -98,10 +98,10 @@ github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841 h1:Zef93z9UiZQwRA
github.com/oneclickvirt/CommonMediaTests v0.0.4-20250329123841/go.mod h1:DAmFPRjFV5p9fEzUUSml5jJGn2f1NZJQCzTxITHDjc4=
github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204 h1:apFaEbHGKflYMZzK17nXzEai4GG873mTd+d9hCO/KdY=
github.com/oneclickvirt/UnlockTests v0.0.28-20250727155204/go.mod h1:oOa6wj/qECtRMxwBO6D7o0L0F0Q/5sQ747OCnFQqoGE=
github.com/oneclickvirt/backtrace v0.0.6-20250801151556 h1:qxCHjNkaUH2z4buO5qrqqXE1XPB0bTU3wfkCEp8G51w=
github.com/oneclickvirt/backtrace v0.0.6-20250801151556/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns=
github.com/oneclickvirt/basics v0.0.15-20250728021329 h1:bXat5W1twZdOdzJ15BFZUYsjAEcTH9ly9oMDIg5+Rbo=
github.com/oneclickvirt/basics v0.0.15-20250728021329/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/backtrace v0.0.6-20250805091811 h1:mKXh/SB+8Aud1TdgmekIXiRR1ZTduIwoCpvrwa5gyyo=
github.com/oneclickvirt/backtrace v0.0.6-20250805091811/go.mod h1:/+KUtOWz48TyiTTbhVTsp3D6b5WY+4pCgvFBYtUGtns=
github.com/oneclickvirt/basics v0.0.15-20250805084236 h1:guYO6wGooSIOAIutuy/zfJ4sXj525nBITw8cjEPRaK8=
github.com/oneclickvirt/basics v0.0.15-20250805084236/go.mod h1:2PV+1ge01zb0Sqzj2V2I7P0wAdFSLF1XgAiumchJJbg=
github.com/oneclickvirt/cputest v0.0.12-20250720122317 h1:toiwAK1hZE5b8klu2mOQ7J4sv5yV9lpPKwgPahfRYBQ=
github.com/oneclickvirt/cputest v0.0.12-20250720122317/go.mod h1:vjlH8tkPFft1tlLOpeNskXVvurxkHaJ3+dgFxQGLXY4=
github.com/oneclickvirt/dd v0.0.2-20250701085922 h1:WiWZwcnCPhRc8hLZdvkjD2kOEpnqn1S31z1j0x3V4l0=
@@ -124,8 +124,8 @@ github.com/oneclickvirt/pingtest v0.0.8-20250728015259 h1:egoxZRZBOWN3JqBwqEsULD
github.com/oneclickvirt/pingtest v0.0.8-20250728015259/go.mod h1:gxwsxxwitNQiGq2OI0ZogYoOLwc8DtuOdSRe6/EvRqs=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900 h1:AomzdppSOFB70AJESQhlp0IPbsHTTJGimAWDk2TzCWM=
github.com/oneclickvirt/portchecker v0.0.3-20250728015900/go.mod h1:9sjMDPCd4Z40wkYB0S9gQPGH8YPtnNE1ZJthVIuHUzA=
github.com/oneclickvirt/security v0.0.6-20250727160145 h1://sqEyAITvv04zXZwWurTkMDMD4nUAl7Wukj5lEDALI=
github.com/oneclickvirt/security v0.0.6-20250727160145/go.mod h1:WpzPJsQFP0uOHmUUsqT9sjNhD5b+1LFd90HiM8cz4nM=
github.com/oneclickvirt/security v0.0.6-20250805090112 h1:lUNtsnpZ3JNLS4xxjFGGECaxA46yNyxbYjdust9W0M4=
github.com/oneclickvirt/security v0.0.6-20250805090112/go.mod h1:JB6SJWm5pbrngCgSTYLd2m4Hj8mHO6mJua1WgHMZOcE=
github.com/oneclickvirt/speedtest v0.0.10-20250728015734 h1:HKO7/JQ74ueXA8Wo8NIvcK9DphbEG/YTfAAVz/akSiY=
github.com/oneclickvirt/speedtest v0.0.10-20250728015734/go.mod h1:0W8vnMbA3iucXLXFdGfe9Ia6RPS0izRO7jvu/SnH1P8=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=

View File

@@ -39,7 +39,7 @@ import (
)
var (
ecsVersion = "v0.1.72"
ecsVersion = "v0.1.73"
menuMode bool
onlyChinaTest bool
input, choice string
@@ -62,6 +62,7 @@ var (
help bool
goecsFlag = flag.NewFlagSet("goecs", flag.ContinueOnError)
finish bool
IPV4, IPV6 string
)
func getMenuChoice(language string) string {
@@ -544,13 +545,13 @@ func runBasicTests(preCheck utils.NetCheckResult, basicInfo, securityInfo *strin
}
}
if preCheck.Connected && preCheck.StackType == "DualStack" {
*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus)
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, nt3CheckType, securityTestStatus)
} else if preCheck.Connected && preCheck.StackType == "IPv4" {
*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv4", securityTestStatus)
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv4", securityTestStatus)
} else if preCheck.Connected && preCheck.StackType == "IPv6" {
*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus)
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "ipv6", securityTestStatus)
} else {
*basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false)
IPV4, IPV6, *basicInfo, *securityInfo, nt3CheckType = utils.BasicsAndSecurityCheck(language, "", false)
securityTestStatus = false
}
if basicStatus {
@@ -691,7 +692,7 @@ func runNetworkTests(wg3 *sync.WaitGroup, ptInfo *string, output, tempOutput str
output = utils.PrintAndCapture(func() {
if backtraceStatus && !onlyChinaTest {
utils.PrintCenteredTitle("上游及回程线路检测", width)
upstreams.UpstreamsCheck()
upstreams.UpstreamsCheck(IPV4)
}
}, tempOutput, output)
output = utils.PrintAndCapture(func() {

View File

@@ -1,77 +1,14 @@
package upstreams
import (
"context"
"encoding/json"
"fmt"
"github.com/imroc/req/v3"
"github.com/oneclickvirt/UnlockTests/uts"
bgptools "github.com/oneclickvirt/backtrace/bgptools"
backtrace "github.com/oneclickvirt/backtrace/bk"
"net"
"os/exec"
"strings"
"time"
)
type IpInfo struct {
Ip string `json:"ip"`
City string `json:"city,omitempty"`
Region string `json:"region,omitempty"`
Country string `json:"country,omitempty"`
Org string `json:"org,omitempty"`
}
func fetchIP(ctx context.Context, url string, parse func([]byte) (string, error), ch chan<- string) {
client := req.C().SetTimeout(3 * time.Second)
resp, err := client.R().SetContext(ctx).Get(url)
if err != nil || !resp.IsSuccessState() {
return
}
ip, err := parse(resp.Bytes())
if err == nil && ip != "" && strings.Contains(ip, ".") {
ch <- ip
}
}
func fetchLocalIP(ctx context.Context, ch chan<- string) {
cmd := exec.CommandContext(ctx, "bash", "-c", "ip addr show | awk '/inet .*global/ && !/inet6/ {print $2}' | sed -n '1p'")
output, err := cmd.Output()
if err != nil {
return
}
ipCidr := strings.TrimSpace(string(output))
if ipCidr != "" {
ip, _, err := net.ParseCIDR(ipCidr)
if err == nil && ip.To4() != nil {
ch <- ip.String()
}
}
}
func UpstreamsCheck() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
ipChan := make(chan string, 4)
go fetchIP(ctx, "https://ipinfo.io", func(b []byte) (string, error) {
var data IpInfo
err := json.Unmarshal(b, &data)
return data.Ip, err
}, ipChan)
go fetchIP(ctx, "https://api.ip.sb/ip", func(b []byte) (string, error) {
return strings.TrimSpace(string(b)), nil
}, ipChan)
go fetchIP(ctx, "http://ip-api.com/json/?fields=query", func(b []byte) (string, error) {
var data struct {
Query string `json:"query"`
}
err := json.Unmarshal(b, &data)
return data.Query, err
}, ipChan)
go fetchLocalIP(ctx, ipChan)
var ip string
select {
case ip = <-ipChan:
case <-ctx.Done():
}
func UpstreamsCheck(ip string) {
if ip != "" {
if result, err := bgptools.GetPoPInfo(ip); err == nil {
fmt.Print(result.Result)

View File

@@ -3,5 +3,5 @@ package upstreams
import "testing"
func TestUpstreamsCheck(t *testing.T) {
UpstreamsCheck()
UpstreamsCheck("148.100.85.25")
}

View File

@@ -100,14 +100,14 @@ func CheckChina(enableLogger bool) bool {
}
// BasicsAndSecurityCheck 执行安全检查
func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string) {
func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus bool) (string, string, string, string, string) {
var wgt sync.WaitGroup
var ipInfo, securityInfo, systemInfo string
var ipv4, ipv6, ipInfo, securityInfo, systemInfo string
var err error
wgt.Add(1)
go func() {
defer wgt.Done()
ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language)
ipv4, ipv6, ipInfo, securityInfo, err = network.NetworkCheck("both", securityCheckStatus, language)
if err != nil {
fmt.Println(err.Error())
}
@@ -119,19 +119,19 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b
}()
wgt.Wait()
basicInfo := systemInfo + ipInfo
if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") {
if strings.Contains(ipInfo, "IPV4") && strings.Contains(ipInfo, "IPV6") && ipv4 != "" && ipv6 != "" {
uts.IPV4 = true
uts.IPV6 = true
if nt3CheckType == "" {
nt3CheckType = "ipv4"
}
} else if strings.Contains(ipInfo, "IPV4") {
} else if strings.Contains(ipInfo, "IPV4") && ipv4 != "" {
uts.IPV4 = true
uts.IPV6 = false
if nt3CheckType == "" {
nt3CheckType = "ipv4"
}
} else if strings.Contains(ipInfo, "IPV6") {
} else if strings.Contains(ipInfo, "IPV6") && ipv6 != "" {
uts.IPV6 = true
uts.IPV4 = false
if nt3CheckType == "" {
@@ -144,7 +144,7 @@ func BasicsAndSecurityCheck(language, nt3CheckType string, securityCheckStatus b
nt3CheckType = "ipv4"
}
basicInfo = strings.ReplaceAll(basicInfo, "\n\n", "\n")
return basicInfo, securityInfo, nt3CheckType
return ipv4, ipv6, basicInfo, securityInfo, nt3CheckType
}
// CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串

View File

@@ -24,7 +24,7 @@ func TestBasicsAndSecurityCheck(t *testing.T) {
} else {
fmt.Println("❌ 本机未检测到公网连接")
}
basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false)
_, _, basicInfo, securityInfo, nt3CheckType := BasicsAndSecurityCheck("zh", "ipv4", false)
fmt.Println(basicInfo)
fmt.Println(securityInfo)
fmt.Println(nt3CheckType)