diff --git a/go.mod b/go.mod index ace43b7..6f37d5e 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,9 @@ require ( github.com/jaypipes/ghw v0.12.0 github.com/json-iterator/go v1.1.12 github.com/libp2p/go-nat v0.2.0 + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/oneclickvirt/defaultset v0.0.2-20240624082446 - github.com/oneclickvirt/gostun v0.0.3-20240702054621 + github.com/oneclickvirt/gostun v0.0.3-20250329105202 github.com/shirou/gopsutil/v4 v4.24.5 github.com/yusufpapurcu/wmi v1.2.4 golang.org/x/sys v0.21.0 diff --git a/go.sum b/go.sum index 039aee2..85ecd17 100644 --- a/go.sum +++ b/go.sum @@ -62,10 +62,12 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc= github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E= -github.com/oneclickvirt/gostun v0.0.3-20240702054621 h1:IE89eEYV9TJbF94SakQDAxTLIaqX+Tb6ZhJ/CCIP+90= -github.com/oneclickvirt/gostun v0.0.3-20240702054621/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA= +github.com/oneclickvirt/gostun v0.0.3-20250329105202 h1:aJ6E91Lp94lq8iWRcCaxpXTjqOOaWvufr5oras6cFtM= +github.com/oneclickvirt/gostun v0.0.3-20250329105202/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= diff --git a/network/baseinfo/bgp.go b/network/baseinfo/bgp.go new file mode 100644 index 0000000..3f3580f --- /dev/null +++ b/network/baseinfo/bgp.go @@ -0,0 +1,91 @@ +package baseinfo + +import ( + "bytes" + "fmt" + "image/color" + "image/png" + "io" + "math" + "net" + + "github.com/imroc/req/v3" + "github.com/nfnt/resize" +) + +// GetCIDRPrefix 获取 IP 地址的实际 CIDR 前缀,获取失败时返回默认值 24 +func GetCIDRPrefix(ip string) int { + interfaces, err := net.Interfaces() + if err != nil { + return 24 + } + for _, iface := range interfaces { + addrs, err := iface.Addrs() + if err != nil { + continue + } + for _, addr := range addrs { + if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil { + if ipNet.IP.String() == ip { + ones, _ := ipNet.Mask.Size() + return ones + } + } + } + } + return 24 +} + +func GetNeighborCount(ip string, prefixNum int) (int, int, error) { + client := req.C() + client.ImpersonateChrome() + cidrBase := fmt.Sprintf("%s/%d", ip, prefixNum) + neighborTotal := int(math.Pow(2, float64(32-prefixNum))) + neighborActive, err := countActiveIPs(client, fmt.Sprintf("https://bgp.tools/pfximg/%s", cidrBase)) + if err != nil { + return 0, 0, err + } + // ipTotal := int(math.Pow(2, float64(32-prefixNum))) + // ipActive, err := countActiveIPs(client, fmt.Sprintf("https://bgp.tools/pfximg/%s", ip)) + // if err != nil { + // return 0, 0, err + // } + // fmt.Printf("Active IPs: %d/%d\n", ipActive, ipTotal) + return neighborActive, neighborTotal, nil +} + +func countActiveIPs(client *req.Client, url string) (int, error) { + resp, err := client.R().Get(url) + if err != nil { + return 0, err + } + if !resp.IsSuccessState() { + return 0, fmt.Errorf("HTTP request failed: %s", resp.Status) + } + // 读取 PNG 数据到内存 + data, err := io.ReadAll(resp.Body) + if err != nil { + return 0, err + } + // 确保数据正确 + if len(data) < 8 || !bytes.HasPrefix(data, []byte("\x89PNG\r\n\x1a\n")) { + return 0, fmt.Errorf("invalid PNG format") + } + // 解码 PNG + img, err := png.Decode(bytes.NewReader(data)) + if err != nil { + return 0, fmt.Errorf("failed to decode PNG: %w", err) + } + // 调整图像大小 + resizedImg := resize.Resize(0, 100, img, resize.Lanczos3) + count := 0 + for y := 0; y < resizedImg.Bounds().Dy(); y++ { + for x := 0; x < resizedImg.Bounds().Dx(); x++ { + c := color.RGBAModel.Convert(resizedImg.At(x, y)).(color.RGBA) + if c.R == 0 && c.G == 3 && c.B == 255 { + count++ + } + } + } + return count, nil +} diff --git a/network/baseinfo/bgp_test.go b/network/baseinfo/bgp_test.go new file mode 100644 index 0000000..49bb8f7 --- /dev/null +++ b/network/baseinfo/bgp_test.go @@ -0,0 +1,17 @@ +package baseinfo + +import ( + "fmt" + "testing" +) + +func TestNeighborCount(t *testing.T) { + ip := "54.92.128.0" // 示例 IP + prefixNum := 24 // 示例前缀 + neighborActive, neighborTotal, err := GetNeighborCount(ip, prefixNum) + if err != nil { + fmt.Println("Error:", err) + return + } + fmt.Printf("Neighbor Active: %d/%d\n", neighborActive, neighborTotal) +} diff --git a/network/network.go b/network/network.go index 191a23a..43dff84 100644 --- a/network/network.go +++ b/network/network.go @@ -2,7 +2,6 @@ package network import ( "fmt" - "strings" "github.com/oneclickvirt/basics/model" "github.com/oneclickvirt/basics/network/baseinfo" @@ -10,35 +9,43 @@ import ( ) // sortAndTranslateText 对原始文本进行排序和翻译 -func sortAndTranslateText(orginList []string, language string, fields []string) string { - var result string - for _, key := range fields { - var displayKey string - if language == "zh" { - displayKey = model.TranslationMap[key] - if displayKey == "" { - displayKey = key - } - } else { - displayKey = key - } - for _, line := range orginList { - if strings.Contains(line, key) { - if displayKey == key { - result = result + line + "\n" - } else { - result = result + strings.ReplaceAll(line, key, displayKey) + "\n" - } - break - } - } - } - return result -} +// func sortAndTranslateText(orginList []string, language string, fields []string) string { +// var result string +// for _, key := range fields { +// var displayKey string +// if language == "zh" { +// displayKey = model.TranslationMap[key] +// if displayKey == "" { +// displayKey = key +// } +// } else { +// displayKey = key +// } +// for _, line := range orginList { +// if strings.Contains(line, key) { +// if displayKey == key { +// result = result + line + "\n" +// } else { +// result = result + strings.ReplaceAll(line, key, displayKey) + "\n" +// } +// break +// } +// } +// } +// return result +// } // processPrintIPInfo 处理IP信息 -func processPrintIPInfo(headASNString string, headLocationString string, ipResult *model.IpInfo) string { +func processPrintIPInfo(ipVersion string, ipResult *model.IpInfo) string { var info string + var headASNString, headLocationString string + if ipVersion == "ipv4" { + headASNString = " IPV4 ASN : " + headLocationString = " IPV4 Location : " + } else if ipVersion == "ipv6" { + headASNString = " IPV6 ASN : " + headLocationString = " IPV6 Location : " + } // 处理ASN信息 if ipResult.ASN != "" || ipResult.Org != "" { info += headASNString @@ -64,6 +71,14 @@ func processPrintIPInfo(headASNString string, headLocationString string, ipResul } info += "\n" } + // 仅处理 IPv4 的邻居信息 + if ipVersion == "ipv4" && ipResult.Ip != "" { + prefixNum := baseinfo.GetCIDRPrefix(ipResult.Ip) + neighborActive, neighborTotal, err := baseinfo.GetNeighborCount(ipResult.Ip, prefixNum) + if err == nil { + info += fmt.Sprintf(" IPV4 Active IPs : %d/%d (CIDR /%d)\n", neighborActive, neighborTotal, prefixNum) + } + } return info } @@ -82,10 +97,10 @@ func NetworkCheck(checkType string, enableSecurityCheck bool, language string) ( Logger.Info(err.Error()) } if ipInfoV4Result != nil { - ipInfo += processPrintIPInfo(" IPV4 ASN : ", " IPV4 Location : ", ipInfoV4Result) + ipInfo += processPrintIPInfo("ipv4", ipInfoV4Result) } if ipInfoV6Result != nil { - ipInfo += processPrintIPInfo(" IPV6 ASN : ", " IPV6 Location : ", ipInfoV6Result) + ipInfo += processPrintIPInfo("ipv6", ipInfoV6Result) } return ipInfo, "", nil } else if checkType == "ipv4" { @@ -94,7 +109,7 @@ func NetworkCheck(checkType string, enableSecurityCheck bool, language string) ( Logger.Info(err.Error()) } if ipInfoV4Result != nil { - ipInfo += processPrintIPInfo(" IPV4 ASN : ", " IPV4 Location : ", ipInfoV4Result) + ipInfo += processPrintIPInfo("ipv4", ipInfoV4Result) } return ipInfo, "", nil } else if checkType == "ipv6" { @@ -103,7 +118,7 @@ func NetworkCheck(checkType string, enableSecurityCheck bool, language string) ( Logger.Info(err.Error()) } if ipInfoV6Result != nil { - ipInfo += processPrintIPInfo(" IPV6 ASN : ", " IPV6 Location : ", ipInfoV6Result) + ipInfo += processPrintIPInfo("ipv6", ipInfoV6Result) } return ipInfo, "", nil } diff --git a/system/system.go b/system/system.go index f422e54..b96fbe4 100644 --- a/system/system.go +++ b/system/system.go @@ -115,6 +115,7 @@ func CheckSystemInfo(language string) string { if ret.TcpAccelerationMethod != "" { res += " Tcp Accelerate : " + ret.TcpAccelerationMethod + "\n" } + } else if language == "zh" { res += " CPU 型号 : " + ret.CpuModel + "\n" res += " CPU 数量 : " + ret.CpuCores + "\n"