diff --git a/README.md b/README.md index d30ef82d..de973546 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/README_NEW_USER.md b/README_NEW_USER.md index 507ccc48..36d28b39 100644 --- a/README_NEW_USER.md +++ b/README_NEW_USER.md @@ -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** | 其他类型的直接或间接连接,如 IX(Internet 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单核满血性能 ### **三网回程路由检测** -默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的说明。 +默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的参数说明。 -主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。 +主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。有时候路由信息完全藏起来了,只知道实际使用的延迟低,实际可能也是优质线路只是查不到信息,这就没办法直接识别了。 ### **就近测速** diff --git a/go.mod b/go.mod index ef972b47..f83299cd 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index 73d7c57d..a41a721a 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/goecs.go b/goecs.go index 97cb6193..7741c524 100644 --- a/goecs.go +++ b/goecs.go @@ -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() { diff --git a/upstreams/upstreams.go b/upstreams/upstreams.go index 5d6075f5..c3bff2e5 100644 --- a/upstreams/upstreams.go +++ b/upstreams/upstreams.go @@ -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) diff --git a/upstreams/uptreams_test.go b/upstreams/uptreams_test.go index debd0ff9..0545b594 100644 --- a/upstreams/uptreams_test.go +++ b/upstreams/uptreams_test.go @@ -3,5 +3,5 @@ package upstreams import "testing" func TestUpstreamsCheck(t *testing.T) { - UpstreamsCheck() + UpstreamsCheck("148.100.85.25") } diff --git a/utils/utils.go b/utils/utils.go index 0366b49e..7e23fc17 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -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 捕获函数输出和错误输出,实时输出,并返回字符串 diff --git a/utils/utils_test.go b/utils/utils_test.go index 19e1e4bc..58fbe18e 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -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)