mirror of
https://github.com/oneclickvirt/ecs.git
synced 2025-10-22 06:50:09 +08:00
fix: 修复上游识别,支持直接导入basics识别到的IP地址,而不再重新获取IP地址减少等待时间
This commit is contained in:
@@ -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)
|
||||
|
@@ -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单核满血性能
|
||||
|
||||
### **三网回程路由检测**
|
||||
|
||||
默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的说明。
|
||||
默认检测广州为目的地,实际可使用命令行参数指定目的地,见对应的参数说明。
|
||||
|
||||
主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。
|
||||
主要就是看是不是直连,是不是延迟低,是不是没有隐藏路由信息。如果路由全球跑,延迟起飞,那么线路自然不会好到哪里去。有时候路由信息完全藏起来了,只知道实际使用的延迟低,实际可能也是优质线路只是查不到信息,这就没办法直接识别了。
|
||||
|
||||
### **就近测速**
|
||||
|
||||
|
6
go.mod
6
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
|
||||
)
|
||||
|
||||
|
12
go.sum
12
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=
|
||||
|
13
goecs.go
13
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() {
|
||||
|
@@ -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)
|
||||
|
@@ -3,5 +3,5 @@ package upstreams
|
||||
import "testing"
|
||||
|
||||
func TestUpstreamsCheck(t *testing.T) {
|
||||
UpstreamsCheck()
|
||||
UpstreamsCheck("148.100.85.25")
|
||||
}
|
||||
|
@@ -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 捕获函数输出和错误输出,实时输出,并返回字符串
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user