feat: 添加活跃邻居BGP检测

This commit is contained in:
spiritlhl
2025-03-29 11:44:08 +00:00
parent 4ad9efddbe
commit f01e96bb62
6 changed files with 161 additions and 34 deletions

3
go.mod
View File

@@ -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

6
go.sum
View File

@@ -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=

91
network/baseinfo/bgp.go Normal file
View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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"