This commit is contained in:
spiritlhl
2024-05-04 08:17:38 +00:00
parent 81df379022
commit 52bb9b9db6
23 changed files with 1409 additions and 0 deletions

7
cmd/main.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "github.com/oneclickvirt/basics/system"
func main() {
system.GetSystemInfo()
}

35
defaultset/defaultset.go Normal file
View File

@@ -0,0 +1,35 @@
package defaultset
import "fmt"
func Red(text string) string {
return fmt.Sprintf("\033[31m\033[01m%s\033[0m", text)
}
func Green(text string) string {
return fmt.Sprintf("\033[32m\033[01m%s\033[0m", text)
}
func DarkGreen(text string) string {
return fmt.Sprintf("\033[32m\033[02m%s\033[0m", text)
}
func Yellow(text string) string {
return fmt.Sprintf("\033[33m\033[01m%s\033[0m", text)
}
func Blue(text string) string {
return fmt.Sprintf("\033[36m\033[01m%s\033[0m", text)
}
func Purple(text string) string {
return fmt.Sprintf("\033[35m\033[01m%s\033[0m", text)
}
func Cyan(text string) string {
return fmt.Sprintf("\033[36m\033[01m%s\033[0m", text)
}
func White(text string) string {
return fmt.Sprintf("\033[37m\033[01m%s\033[0m", text)
}

24
go.mod Normal file
View File

@@ -0,0 +1,24 @@
module github.com/oneclickvirt/basics
go 1.21.5
require (
github.com/libp2p/go-nat v0.2.0
github.com/shirou/gopsutil v3.21.11+incompatible
)
require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/huin/goupnp v1.2.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.19.0 // indirect
)

50
go.sum Normal file
View File

@@ -0,0 +1,50 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY=
github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,254 @@
package baseinfo
import (
"fmt"
"github.com/oneclickvirt/basics/network/model"
"github.com/oneclickvirt/basics/network/utils"
"strconv"
"strings"
"sync"
)
// FetchIPInfoIo 从 ipinfo.io 获取 IP 信息
func FetchIPInfoIo(netType string) (*model.IpInfo, *model.SecurityInfo, error) {
data, err := utils.FetchJsonFromURL("http://ipinfo.io", netType, false, "")
if err == nil {
res := &model.IpInfo{}
if ip, ok := data["ip"].(string); ok && ip != "" {
res.Ip = ip
}
if city, ok := data["city"].(string); ok && city != "" {
res.City = city
}
if region, ok := data["region"].(string); ok && region != "" {
res.Region = region
}
if country, ok := data["country"].(string); ok && country != "" {
res.Country = country
}
if org, ok := data["org"].(string); ok && org != "" {
parts := strings.Split(org, " ")
if len(parts) > 0 {
res.ASN = parts[0]
res.Org = strings.Join(parts[1:], " ")
} else {
res.ASN = org
}
}
return res, nil, nil
} else {
return nil, nil, err
}
}
// FetchCloudFlare 从 speed.cloudflare.com 获取 IP 信息
func FetchCloudFlare(netType string) (*model.IpInfo, *model.SecurityInfo, error) {
data, err := utils.FetchJsonFromURL("https://speed.cloudflare.com/meta", netType, false, "")
if err == nil {
res := &model.IpInfo{}
if ip, ok := data["clientIp"].(string); ok && ip != "" {
res.Ip = ip
}
if city, ok := data["city"].(string); ok && city != "" {
res.City = city
}
if region, ok := data["region"].(string); ok && region != "" {
res.Region = region
}
if country, ok := data["country"].(string); ok && country != "" {
res.Country = country
}
if asnFloat, ok := data["asn"].(float64); ok {
res.ASN = strconv.FormatInt(int64(asnFloat), 10)
} else if asnStr, ok := data["asn"].(string); ok && asnStr != "" {
res.ASN = asnStr
}
if org, ok := data["asOrganization"].(string); ok && org != "" {
res.Org = org
}
return res, nil, nil
} else {
return nil, nil, err
}
}
// FetchIpSb 从 api.ip.sb 获取 IP 信息
func FetchIpSb(netType string) (*model.IpInfo, *model.SecurityInfo, error) {
data, err := utils.FetchJsonFromURL("https://api.ip.sb/geoip", netType, true, "")
if err == nil {
res := &model.IpInfo{}
if ip, ok := data["ip"].(string); ok && ip != "" {
res.Ip = ip
}
if city, ok := data["city"].(string); ok && city != "" {
res.City = city
}
if region, ok := data["region"].(string); ok && region != "" {
res.Region = region
}
if country, ok := data["country"].(string); ok && country != "" {
res.Country = country
}
if asnFloat, ok := data["asn"].(float64); ok {
res.ASN = strconv.FormatInt(int64(asnFloat), 10)
} else if asnStr, ok := data["asn"].(string); ok && asnStr != "" {
res.ASN = asnStr
}
if org, ok := data["asn_organization"].(string); ok && org != "" {
res.Org = org
}
return res, nil, nil
} else {
return nil, nil, err
}
}
// FetchIpDataCheerVision 从 ipdata.cheervision.co 获取 IP 信息
func FetchIpDataCheerVision(netType string) (*model.IpInfo, *model.SecurityInfo, error) {
data, err := utils.FetchJsonFromURL("https://ipdata.cheervision.co", netType, true, "")
if err == nil {
ipInfo := utils.ParseIpInfo(data)
securityInfo := utils.ParseSecurityInfo(data)
return ipInfo, securityInfo, nil
} else {
return nil, nil, err
}
}
// executeFunctions 并发执行函数
// 仅区分IPV4或IPV6BOTH的情况需要两次执行本函数分别指定
func executeFunctions(checkType string, fetchFunc func(string) (*model.IpInfo, *model.SecurityInfo, error), ipInfoChan chan *model.IpInfo, securityInfoChan chan *model.SecurityInfo, wg *sync.WaitGroup) {
defer wg.Done()
ipFetcher := func(ipType string) {
ipInfo, securityInfo, err := fetchFunc(ipType)
if err == nil {
select {
case ipInfoChan <- ipInfo:
default:
}
select {
case securityInfoChan <- securityInfo:
default:
}
} else {
select {
case ipInfoChan <- nil:
default:
}
select {
case securityInfoChan <- nil:
default:
}
}
}
if checkType == "ipv4" {
wg.Add(1)
go func() {
defer wg.Done()
ipFetcher("tcp4")
}()
}
if checkType == "ipv6" {
wg.Add(1)
go func() {
defer wg.Done()
ipFetcher("tcp6")
}()
}
}
// RunIpCheck 并发请求获取信息
func RunIpCheck(checkType string) (*model.IpInfo, *model.SecurityInfo, *model.IpInfo, *model.SecurityInfo, error) {
// 定义函数名数组
functions := []func(string) (*model.IpInfo, *model.SecurityInfo, error){
FetchIPInfoIo,
FetchCloudFlare,
FetchIpSb,
FetchIpDataCheerVision,
}
// 定义通道
ipInfoIPv4 := make(chan *model.IpInfo, len(functions))
securityInfoIPv4 := make(chan *model.SecurityInfo, len(functions))
ipInfoIPv6 := make(chan *model.IpInfo, len(functions))
securityInfoIPv6 := make(chan *model.SecurityInfo, len(functions))
var wg sync.WaitGroup
if checkType == "both" {
wg.Add(len(functions) * 2) // 每个函数都会产生一个 IPv4 和一个 IPv6 结果
// 启动协程执行函数
for _, f := range functions {
go executeFunctions("ipv4", f, ipInfoIPv4, securityInfoIPv4, &wg)
go executeFunctions("ipv6", f, ipInfoIPv6, securityInfoIPv6, &wg)
}
} else if checkType == "ipv4" {
wg.Add(len(functions)) // 每个函数都会产生一个 IPv4 结果
// 启动协程执行函数
for _, f := range functions {
go executeFunctions("ipv4", f, ipInfoIPv4, securityInfoIPv4, &wg)
}
} else if checkType == "ipv6" {
wg.Add(len(functions)) // 每个函数都会产生一个 IPv6 结果
// 启动协程执行函数
for _, f := range functions {
go executeFunctions("ipv6", f, ipInfoIPv6, securityInfoIPv6, &wg)
}
} else {
return nil, nil, nil, nil, fmt.Errorf("wrong checkType")
}
go func() {
wg.Wait()
close(ipInfoIPv4)
close(securityInfoIPv4)
close(ipInfoIPv6)
close(securityInfoIPv6)
}()
// 读取结果并处理
var ipInfoV4Result *model.IpInfo
var ipInfoV6Result *model.IpInfo
var securityInfoV4Result *model.SecurityInfo
var securityInfoV6Result *model.SecurityInfo
for ipInfo := range ipInfoIPv4 {
if ipInfo != nil {
if ipInfoV4Result == nil {
ipInfoV4Result = &model.IpInfo{}
}
ipInfoV4TempResult, err := utils.CompareAndMergeIpInfo(ipInfoV4Result, ipInfo)
if err == nil {
ipInfoV4Result = ipInfoV4TempResult
}
}
}
for ipInfo := range ipInfoIPv6 {
if ipInfo != nil {
if ipInfoV6Result == nil {
ipInfoV6Result = &model.IpInfo{}
}
ipInfoV6TempResult, err := utils.CompareAndMergeIpInfo(ipInfoV6Result, ipInfo)
if err == nil {
ipInfoV6Result = ipInfoV6TempResult
}
}
}
for securityInfo := range securityInfoIPv4 {
if securityInfo != nil {
if securityInfoV4Result == nil {
securityInfoV4Result = &model.SecurityInfo{}
}
securityInfoV4TempResult, err := utils.CompareAndMergeSecurityInfo(securityInfoV4Result, securityInfo)
if err == nil {
securityInfoV4Result = securityInfoV4TempResult
}
}
}
for securityInfo := range securityInfoIPv6 {
if securityInfo != nil {
if securityInfoV6Result == nil {
securityInfoV6Result = &model.SecurityInfo{}
}
securityInfoV6TempResult, err := utils.CompareAndMergeSecurityInfo(securityInfoV6Result, securityInfo)
if err == nil {
securityInfoV6Result = securityInfoV6TempResult
}
}
}
return ipInfoV4Result, securityInfoV4Result, ipInfoV6Result, securityInfoV6Result, nil
}

View File

@@ -0,0 +1,82 @@
package baseinfo
import (
"fmt"
networkModel "github.com/oneclickvirt/basics/network/model"
"testing"
"time"
)
// printIPInfo 重构输出函数
func printIPInfo(ipInfo *networkModel.IpInfo, securityInfo *networkModel.SecurityInfo, err error) {
if err != nil {
fmt.Println("获取 IP 信息时出错:", err)
return
}
if ipInfo != nil {
fmt.Println("IPInfo:")
fmt.Println("IP:", ipInfo.Ip)
fmt.Println("ASN:", ipInfo.ASN)
fmt.Println("Org:", ipInfo.Org)
fmt.Println("Country:", ipInfo.Country)
fmt.Println("Region:", ipInfo.Region)
fmt.Println("City:", ipInfo.City)
fmt.Println("---------------------------------")
}
if securityInfo != nil {
fmt.Println("Security Info:")
fmt.Println("IsAbuser:", securityInfo.IsAbuser)
fmt.Println("IsAttacker:", securityInfo.IsAttacker)
fmt.Println("IsBogon:", securityInfo.IsBogon)
fmt.Println("IsCloudProvider:", securityInfo.IsCloudProvider)
fmt.Println("IsProxy:", securityInfo.IsProxy)
fmt.Println("IsRelay:", securityInfo.IsRelay)
fmt.Println("IsTor:", securityInfo.IsTor)
fmt.Println("IsTorExit:", securityInfo.IsTorExit)
fmt.Println("IsVpn:", securityInfo.IsVpn)
fmt.Println("IsAnonymous:", securityInfo.IsAnonymous)
fmt.Println("IsThreat:", securityInfo.IsThreat)
fmt.Println("---------------------------------")
}
}
func TestIPInfo(t *testing.T) {
// Test for IPv4
fmt.Println("IPv4 Testing:")
startV4 := time.Now()
ipInfoV4Result, securityInfoV4Result, _, _, err := RunIpCheck("ipv4")
elapsedV4 := time.Since(startV4)
if err == nil {
fmt.Println("IPv4:")
fmt.Println("------")
printIPInfo(ipInfoV4Result, securityInfoV4Result, nil)
}
fmt.Println("---***********************************---")
// Test for IPv6
fmt.Println("IPv6 Testing:")
startV6 := time.Now()
ipInfoV6Result, securityInfoV6Result, _, _, err := RunIpCheck("ipv6")
elapsedV6 := time.Since(startV6)
if err == nil {
fmt.Println("IPv6:")
fmt.Println("------")
printIPInfo(ipInfoV6Result, securityInfoV6Result, nil)
}
fmt.Println("---***********************************---")
// Test for both IPv4 and IPv6
fmt.Println("Both Testing:")
startBoth := time.Now()
ipInfoV4Result, securityInfoV4Result, ipInfoV6Result, securityInfoV6Result, err = RunIpCheck("both")
elapsedBoth := time.Since(startBoth)
if err == nil {
fmt.Println("IPv4:")
fmt.Println("------")
printIPInfo(ipInfoV4Result, securityInfoV4Result, nil)
fmt.Println("IPv6:")
fmt.Println("------")
printIPInfo(ipInfoV6Result, securityInfoV6Result, nil)
}
fmt.Printf("IPv4 test took %s\n", elapsedV4)
fmt.Printf("IPv6 test took %s\n", elapsedV6)
fmt.Printf("Both test took %s\n", elapsedBoth)
}

0
network/baseinfo/ecs.log Normal file
View File

90
network/model/model.go Normal file
View File

@@ -0,0 +1,90 @@
package model
type IpInfo struct {
Ip string
ASN string
Org string
Country string
Region string
City string
}
type SecurityScore struct {
Tag string
Reputation *int
TrustScore *int
VpnScore *int
ProxyScore *int
CommunityVoteHarmless *int
CommunityVoteMalicious *int
CloudFlareRisk *int // 还没有加入
ThreatScore *int
FraudScore *int
AbuseScore *int
HarmlessnessRecords *int
MaliciousRecords *int
SuspiciousRecords *int
NoRecords *int
}
type SecurityInfo struct {
Tag string
ASNAbuseScore string // 这三个实际是得分类型,但由于是字符串所以还在这解析
CompannyAbuseScore string
ThreatLevel string
UsageType string // connection_type、usage_type、asn_type
CompanyType string // company type
IsCloudProvider string
IsDatacenter string // datacenter、server、hosting
IsMobile string
IsProxy string // Public Proxy、Web Proxy
IsVpn string
IsTor string
IsTorExit string
IsCrawler string
IsAnonymous string
IsAttacker string
IsAbuser string
IsThreat string
IsRelay string // icloud_relay、is_relay
IsBogon string
IsBot string // Search Engine Robot
}
// TranslationMap 定义英文到中文的映射表
var TranslationMap = map[string]string{
"Reputation": "声誉(越高越好)",
"TrustScore": "信任得分(越高越好)",
"VpnScore": "VPN得分(越低越好)",
"ProxyScore": "代理得分(越低越好)",
"CommunityVoteHarmless": "社区投票-无害",
"CommunityVoteMalicious": "社区投票-恶意",
"CloudFlareRisk": "CloudFlare风险(越低越好)",
"ThreatScore": "威胁得分(越低越好)",
"FraudScore": "欺诈得分(越低越好)",
"AbuseScore": "滥用得分(越低越好)",
"HarmlessnessRecords": "无害记录数",
"MaliciousRecords": "恶意记录数",
"SuspiciousRecords": "可疑记录数",
"NoRecords": "无记录数",
"ASNAbuseScore": "ASN滥用得分(越低越好)",
"CompannyAbuseScore": "公司滥用得分(越低越好)",
"ThreatLevel": "威胁级别",
"UsageType": "使用类型",
"CompanyType": "公司类型",
"IsCloudProvider": "是否云提供商",
"IsDatacenter": "是否数据中心",
"IsMobile": "是否移动设备",
"IsProxy": "是否代理",
"IsVpn": "是否VPN",
"IsTor": "是否Tor",
"IsTorExit": "是否Tor出口",
"IsCrawler": "是否网络爬虫",
"IsAnonymous": "是否匿名",
"IsAttacker": "是否攻击者",
"IsAbuser": "是否滥用者",
"IsThreat": "是否威胁",
"IsRelay": "是否中继",
"IsBogon": "是否Bogon",
"IsBot": "是否机器人",
}

97
network/network.go Normal file
View File

@@ -0,0 +1,97 @@
package network
import (
"fmt"
"strings"
"github.com/oneclickvirt/basics/network/baseinfo"
"github.com/oneclickvirt/basics/network/model"
)
// 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
}
// processPrintIPInfo 处理IP信息
func processPrintIPInfo(headASNString string, headLocationString string, ipResult *model.IpInfo) string {
var info string
// 处理ASN信息
if ipResult.ASN != "" || ipResult.Org != "" {
info += headASNString
if ipResult.ASN != "" {
info += "AS" + ipResult.ASN
if ipResult.Org != "" {
info += " "
}
}
info += ipResult.Org + "\n"
}
// 处理位置信息
if ipResult.City != "" || ipResult.Region != "" || ipResult.Country != "" {
info += headLocationString
if ipResult.City != "" {
info += ipResult.City + " / "
}
if ipResult.Region != "" {
info += ipResult.Region + " / "
}
if ipResult.Country != "" {
info += ipResult.Country
}
info += "\n"
}
return info
}
// NetworkCheck 查询网络信息
// checkType 可选 both ipv4 ipv6
// language 暂时仅支持 en 或 zh
func NetworkCheck(checkType string, enableSecurityCheck bool, language string) (string, string, error) {
var ipInfo string
if checkType == "both" {
ipInfoV4Result, _, ipInfoV6Result, _, _ := baseinfo.RunIpCheck("both")
if ipInfoV4Result != nil {
ipInfo += processPrintIPInfo(" IPV4 ASN: ", " IPV4 Location: ", ipInfoV4Result)
}
if ipInfoV6Result != nil {
ipInfo += processPrintIPInfo(" IPV6 ASN: ", " IPV6 Location: ", ipInfoV6Result)
}
return ipInfo, "", nil
} else if checkType == "ipv4" {
ipInfoV4Result, _, _, _, _ := baseinfo.RunIpCheck("ipv4")
if ipInfoV4Result != nil {
ipInfo += processPrintIPInfo(" IPV4 ASN: ", " IPV4 Location: ", ipInfoV4Result)
}
return ipInfo, "", nil
} else if checkType == "ipv6" {
_, _, ipInfoV6Result, _, _ := baseinfo.RunIpCheck("ipv6")
if ipInfoV6Result != nil {
ipInfo += processPrintIPInfo(" IPV6 ASN: ", " IPV6 Location: ", ipInfoV6Result)
}
return ipInfo, "", nil
}
return "", "", fmt.Errorf("wrong in NetworkCheck")
}

14
network/network_test.go Normal file
View File

@@ -0,0 +1,14 @@
package network
import (
"fmt"
"testing"
)
func TestIpv4SecurityCheck(t *testing.T) {
// 全项测试
ipInfo, _, _ := NetworkCheck("both", false, "zh")
fmt.Println("--------------------------------------------------")
fmt.Printf(ipInfo)
fmt.Println("--------------------------------------------------")
}

54
network/utils/merge.go Normal file
View File

@@ -0,0 +1,54 @@
package utils
import (
"fmt"
networkModel "github.com/oneclickvirt/basics/network/model"
)
// chooseString 用于选择非空字符串
func chooseString(src, dst string) string {
if src != "" {
return src
}
return dst
}
// CompareAndMergeIpInfo 用于比较和合并两个 IpInfo 结构体
func CompareAndMergeIpInfo(dst, src *networkModel.IpInfo) (res *networkModel.IpInfo, err error) {
if src == nil {
return nil, fmt.Errorf("Error merge IpInfo")
}
if dst == nil {
dst = &networkModel.IpInfo{}
}
dst.Ip = chooseString(src.Ip, dst.Ip)
dst.ASN = chooseString(src.ASN, dst.ASN)
dst.Org = chooseString(src.Org, dst.Org)
dst.Country = chooseString(src.Country, dst.Country)
dst.Region = chooseString(src.Region, dst.Region)
dst.City = chooseString(src.City, dst.City)
return dst, nil
}
// CompareAndMergeSecurityInfo 用于比较和合并两个 SecurityInfo 结构体
func CompareAndMergeSecurityInfo(dst, src *networkModel.SecurityInfo) (res *networkModel.SecurityInfo, err error) {
if src == nil {
return nil, fmt.Errorf("Error merge SecurityInfo")
}
if dst == nil {
dst = &networkModel.SecurityInfo{}
}
dst.IsAbuser = chooseString(src.IsAbuser, dst.IsAbuser)
dst.IsAttacker = chooseString(src.IsAttacker, dst.IsAttacker)
dst.IsBogon = chooseString(src.IsBogon, dst.IsBogon)
dst.IsCloudProvider = chooseString(src.IsCloudProvider, dst.IsCloudProvider)
dst.IsProxy = chooseString(src.IsProxy, dst.IsProxy)
dst.IsRelay = chooseString(src.IsRelay, dst.IsRelay)
dst.IsTor = chooseString(src.IsTor, dst.IsTor)
dst.IsTorExit = chooseString(src.IsTorExit, dst.IsTorExit)
dst.IsVpn = chooseString(src.IsVpn, dst.IsVpn)
dst.IsAnonymous = chooseString(src.IsAnonymous, dst.IsAnonymous)
dst.IsThreat = chooseString(src.IsThreat, dst.IsThreat)
return dst, nil
}

86
network/utils/parse.go Normal file
View File

@@ -0,0 +1,86 @@
package utils
import (
networkModel "github.com/oneclickvirt/basics/network/model"
"strconv"
"strings"
)
func ParseIpInfo(data map[string]interface{}) *networkModel.IpInfo {
ipInfo := &networkModel.IpInfo{}
if ip, ok := data["ip"].(string); ok {
ipInfo.Ip = ip
}
if location, ok := data["location"].(map[string]interface{}); ok {
if city, ok := location["city"].(string); ok {
ipInfo.City = city
}
if region, ok := location["region"].(map[string]interface{}); ok {
if name, ok := region["name"].(string); ok {
ipInfo.Region = name
}
}
if country, ok := location["country"].(map[string]interface{}); ok {
if name, ok := country["name"].(string); ok {
ipInfo.Country = name
}
}
}
if connection, ok := data["connection"].(map[string]interface{}); ok {
if asn, ok := connection["asn"].(float64); ok {
ipInfo.ASN = strconv.Itoa(int(asn))
}
if org, ok := connection["organization"].(string); ok {
ipInfo.Org = org
}
}
return ipInfo
}
func ParseSecurityInfo(data map[string]interface{}) *networkModel.SecurityInfo {
securityInfo := &networkModel.SecurityInfo{}
if security, ok := data["security"].(map[string]interface{}); ok {
if isAbuser, ok := security["is_abuser"].(bool); ok {
securityInfo.IsAbuser = strconv.FormatBool(isAbuser)
}
if isAttacker, ok := security["is_attacker"].(bool); ok {
securityInfo.IsAttacker = strconv.FormatBool(isAttacker)
}
if isBogon, ok := security["is_bogon"].(bool); ok {
securityInfo.IsBogon = strconv.FormatBool(isBogon)
}
if isCloudProvider, ok := security["is_cloud_provider"].(bool); ok {
securityInfo.IsCloudProvider = strconv.FormatBool(isCloudProvider)
}
if isProxy, ok := security["is_proxy"].(bool); ok {
securityInfo.IsProxy = strconv.FormatBool(isProxy)
}
if isRelay, ok := security["is_relay"].(bool); ok {
securityInfo.IsRelay = strconv.FormatBool(isRelay)
}
if isTor, ok := security["is_tor"].(bool); ok {
securityInfo.IsTor = strconv.FormatBool(isTor)
}
if isTorExit, ok := security["is_tor_exit"].(bool); ok {
securityInfo.IsTorExit = strconv.FormatBool(isTorExit)
}
if isVpn, ok := security["is_vpn"].(bool); ok {
securityInfo.IsVpn = strconv.FormatBool(isVpn)
}
if isAnonymous, ok := security["is_anonymous"].(bool); ok {
securityInfo.IsAnonymous = strconv.FormatBool(isAnonymous)
}
if isThreat, ok := security["is_threat"].(bool); ok {
securityInfo.IsThreat = strconv.FormatBool(isThreat)
}
}
return securityInfo
}
// ParseYesNo 检测文本内容含No则返回No否则返回Yes
func ParseYesNo(text string) string {
if strings.Contains(strings.ToLower(text), "no") {
return "No"
}
return "Yes"
}

93
network/utils/utils.go Normal file
View File

@@ -0,0 +1,93 @@
package utils
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"reflect"
"strings"
"time"
)
// FetchJsonFromURL 函数用于从指定的 URL 获取信息
// url 参数表示要获取信息的 URL
// netType 参数表示网络类型,只能为 "tcp4" 或 "tcp6"。
// enableHeader 参数表示是否启用请求头信息。
// additionalHeader 参数表示传入的额外的请求头信息(用于传输api的key)。
// 返回一个解析 json 得到的 map 和 一个可能发生的错误 。
func FetchJsonFromURL(url, netType string, enableHeader bool, additionalHeader string) (map[string]interface{}, error) {
// 检查网络类型是否有效
if netType != "tcp4" && netType != "tcp6" {
return nil, fmt.Errorf("Invalid netType: %s. Expected 'tcp4' or 'tcp6'.", netType)
}
// 创建 HTTP 客户端
client := &http.Client{
Timeout: 6 * time.Second,
Transport: &http.Transport{
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, netType, addr)
},
TLSHandshakeTimeout: 3 * time.Second,
ResponseHeaderTimeout: 3 * time.Second,
ExpectContinueTimeout: 3 * time.Second,
},
}
// 创建 HTTP 请求
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("Error creating request: %v", err)
}
// 如果启用请求头,则设置请求头信息
if enableHeader {
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
if additionalHeader != "" {
tempList := strings.Split(additionalHeader, ":")
if len(tempList) == 2 {
req.Header.Set(tempList[0], tempList[1])
} else if len(tempList) > 2 {
req.Header.Set(tempList[0], strings.Join(tempList[1:], ":"))
}
}
}
// 执行 HTTP 请求
resp, err := client.Do(req)
if err != nil {
//fmt.Printf("Error fetching %s info: %v \n", url, err)
return nil, fmt.Errorf("Error fetching %s info: %v", url, err)
}
defer resp.Body.Close()
// 解析 JSON 响应体
var data map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
//fmt.Printf("Error decoding %s info: %v \n", url, err)
return nil, fmt.Errorf("Error decoding %s info: %v ", url, err)
}
// 返回解析后的数据和 nil 错误
return data, nil
}
// BoolToString 将布尔值转换为对应的字符串表示true 则返回 "Yes"false 则返回 "No"
func BoolToString(value bool) string {
if value {
return "Yes"
}
return "No"
}
// ExtractFieldNames 获取结构体的属性名字
func ExtractFieldNames(data interface{}) []string {
var fields []string
val := reflect.ValueOf(data).Elem()
for i := 0; i < val.NumField(); i++ {
field := val.Type().Field(i)
name := field.Name
if name != "Tag" {
fields = append(fields, name)
}
}
return fields
}

69
system/cpu_linux.go Normal file
View File

@@ -0,0 +1,69 @@
package system
import (
"fmt"
"os"
"runtime"
"strconv"
"strings"
"github.com/oneclickvirt/basics/system/model"
"github.com/shirou/gopsutil/cpu"
)
func checkCPUFeatureLinux(filename string, feature string) (string, bool) {
content, err := os.ReadFile(filename)
if err != nil {
return "Error reading file", false
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if strings.Contains(line, feature) {
return "✔️ Enabled", true
}
}
return "❌ Disabled", false
}
func checkCPUFeature(filename string, feature string) (string, bool) {
if runtime.GOOS == "linux" {
return checkCPUFeatureLinux(filename, feature)
}
return "Unsupported OS", false
}
func getCpuInfo(ret *model.SystemInfo, cpuType string) (*model.SystemInfo, error) {
var aesFeature, virtFeature, hypervFeature string
var st bool
ci, err := cpu.Info()
if err != nil {
return nil, fmt.Errorf("cpu.Info error: %v", err.Error())
} else {
ret.CpuModel = ""
for i := 0; i < len(ci); i++ {
if len(ret.CpuModel) < len(ci[i].ModelName) {
ret.CpuModel = ci[i].ModelName + fmt.Sprintf("%d %s Core", len(ci), cpuType) + " @ " +
strconv.FormatFloat(ci[i].Mhz, 'f', 2, 64) + " MHz"
ret.CpuCores = fmt.Sprintf("%d vCPU(s)", int(ci[i].Cores))
if ci[i].CacheSize != 0 { // Windows查不到CPU的三缓
ret.CpuCache = string(ci[i].CacheSize)
}
}
}
}
if runtime.GOOS == "windows" {
aesFeature = `HARDWARE\DESCRIPTION\System\CentralProcessor\0`
virtFeature = `HARDWARE\DESCRIPTION\System\CentralProcessor\0`
hypervFeature = `SYSTEM\CurrentControlSet\Control\Hypervisor\0`
} else if runtime.GOOS == "linux" {
aesFeature = "/proc/cpuinfo"
virtFeature = "/proc/cpuinfo"
hypervFeature = "/proc/cpuinfo"
}
ret.CpuAesNi, _ = checkCPUFeature(aesFeature, "aes")
ret.CpuVAH, st = checkCPUFeature(virtFeature, "vmx")
if !st {
ret.CpuVAH, _ = checkCPUFeature(hypervFeature, "hypervisor")
}
return ret, nil
}

96
system/disk.go Normal file
View File

@@ -0,0 +1,96 @@
package system
import (
"github.com/shirou/gopsutil/disk"
"os/exec"
"runtime"
"strconv"
"strings"
)
func getDiskInfo() (string, string, string, error) {
var diskTotalStr, diskUsageStr, bootPath string
tempDiskTotal, tempDiskUsage := getDiskTotalAndUsed()
diskTotalGB := float64(tempDiskTotal) / (1024 * 1024 * 1024)
diskUsageGB := float64(tempDiskUsage) / (1024 * 1024 * 1024)
// 字节为单位 进行单位转换
if diskTotalGB < 1 {
diskTotalStr = strconv.FormatFloat(diskTotalGB*1024, 'f', 2, 64) + " MB"
} else {
diskTotalStr = strconv.FormatFloat(diskTotalGB, 'f', 2, 64) + " GB"
}
if diskUsageGB < 1 {
diskUsageStr = strconv.FormatFloat(diskUsageGB*1024, 'f', 2, 64) + " MB"
} else {
diskUsageStr = strconv.FormatFloat(diskUsageGB, 'f', 2, 64) + " GB"
}
parts, err := disk.Partitions(true)
if err != nil {
bootPath = ""
} else {
for _, part := range parts {
if part.Fstype == "tmpfs" {
continue
}
usageStat, err := disk.Usage(part.Mountpoint)
if err != nil {
continue
}
if usageStat.Total > 0 {
bootPath = part.Mountpoint
break
}
}
}
return diskTotalStr, diskUsageStr, bootPath, nil
}
func getDiskTotalAndUsed() (total uint64, used uint64) {
devices := make(map[string]string)
// 使用默认过滤规则
diskList, _ := disk.Partitions(false)
for _, d := range diskList {
fsType := strings.ToLower(d.Fstype)
// 不统计 K8s 的虚拟挂载点https://github.com/shirou/gopsutil/issues/1007
if devices[d.Device] == "" && isListContainsStr(expectDiskFsTypes, fsType) && !strings.Contains(d.Mountpoint, "/var/lib/kubelet") {
devices[d.Device] = d.Mountpoint
}
}
for _, mountPath := range devices {
diskUsageOf, err := disk.Usage(mountPath)
if err == nil {
total += diskUsageOf.Total
used += diskUsageOf.Used
}
}
// Fallback 到这个方法,仅统计根路径,适用于OpenVZ之类的.
if runtime.GOOS == "linux" && total == 0 && used == 0 {
cmd := exec.Command("df")
out, err := cmd.CombinedOutput()
if err == nil {
s := strings.Split(string(out), "\n")
for _, c := range s {
info := strings.Fields(c)
if len(info) == 6 {
if info[5] == "/" {
total, _ = strconv.ParseUint(info[1], 0, 64)
used, _ = strconv.ParseUint(info[2], 0, 64)
// 默认获取的是1K块为单位的.
total = total * 1024
used = used * 1024
}
}
}
}
}
return
}
func isListContainsStr(list []string, str string) bool {
for i := 0; i < len(list); i++ {
if strings.Contains(str, list[i]) {
return true
}
}
return false
}

52
system/host_linux.go Normal file
View File

@@ -0,0 +1,52 @@
package system
import (
"context"
"fmt"
"runtime"
"time"
"github.com/libp2p/go-nat"
"github.com/shirou/gopsutil/host"
)
func getHostInfo() (string, string, string, string, string, string, string, error) {
var Platform, Kernal, Arch, VmType, NatType string
var cachedBootTime time.Time
hi, err := host.Info()
if err != nil {
println("host.Info error:", err)
} else {
if hi.VirtualizationRole == "guest" {
cpuType = "Virtual"
} else {
cpuType = "Physical"
}
if runtime.GOOS == "linux" {
Platform = hi.Platform
Kernal = hi.PlatformVersion
} else {
Platform = hi.Platform + " " + hi.PlatformVersion
}
Arch = hi.KernelArch
// 查询虚拟化类型
VmType = hi.VirtualizationSystem
// 系统运行时长查询
cachedBootTime = time.Unix(int64(hi.BootTime), 0)
}
uptimeDuration := time.Since(cachedBootTime)
days := int(uptimeDuration.Hours() / 24)
uptimeDuration -= time.Duration(days*24) * time.Hour
hours := int(uptimeDuration.Hours())
uptimeDuration -= time.Duration(hours) * time.Hour
minutes := int(uptimeDuration.Minutes())
uptimeFormatted := fmt.Sprintf("%d days, %02d hours, %02d minutes", days, hours, minutes)
// 查询NAT类型
ctx := context.Background()
gateway, err := nat.DiscoverGateway(ctx)
if err == nil {
natType := gateway.Type()
NatType = natType
}
return cpuType, uptimeFormatted, Platform, Kernal, Arch, VmType, NatType, nil
}

56
system/load_linux.go Normal file
View File

@@ -0,0 +1,56 @@
package system
import (
"bufio"
"os"
"runtime"
"strconv"
"strings"
"github.com/shirou/gopsutil/load"
)
// 获取系统负载信息
func getSystemLoad() (float64, float64, float64, error) {
var load1, load5, load15 float64
var err error
if runtime.GOOS == "linux" {
// 尝试从 /proc/loadavg 文件获取负载信息
load1, load5, load15, err = getLoadFromProc()
if err != nil {
load1, load5, load15 = 0, 0, 0
}
}
// 使用 gopsutil 获取负载
avg, err := load.Avg()
if err != nil {
load1, load5, load15 = 0, 0, 0
} else {
if avg.Load1 != 0 && avg.Load5 != 0 && avg.Load15 != 0 {
load1, load5, load15 = avg.Load1, avg.Load5, avg.Load15
}
}
return load1, load5, load15, nil
}
// getLoadFromProc 从 /proc/loadavg 文件中获取负载信息
func getLoadFromProc() (float64, float64, float64, error) {
file, err := os.Open("/proc/loadavg")
if err != nil {
return 0, 0, 0, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
// 解析负载信息并转换为 float64 类型
load1, _ := strconv.ParseFloat(fields[0], 64)
load5, _ := strconv.ParseFloat(fields[1], 64)
load15, _ := strconv.ParseFloat(fields[2], 64)
return load1, load5, load15, nil
}
if err := scanner.Err(); err != nil {
return 0, 0, 0, err
}
return 0, 0, 0, nil
}

89
system/memory.go Normal file
View File

@@ -0,0 +1,89 @@
package system
import (
"github.com/shirou/gopsutil/mem"
"os"
"runtime"
"strconv"
"strings"
)
func getMemoryInfo() (string, string, string, string, string, string) {
var memoryTotalStr, memoryUsageStr, swapTotalStr, swapUsageStr, virtioBalloonStatus, KernelSamepageMerging string
mv, err := mem.VirtualMemory()
if err != nil {
println("mem.VirtualMemory error:", err)
} else {
memoryTotal := float64(mv.Total)
memoryUsage := float64(mv.Total - mv.Available)
if memoryTotal < 1024*1024*1024 {
memoryTotalStr = strconv.FormatFloat(memoryTotal/(1024*1024), 'f', 2, 64) + " MB"
} else {
memoryTotalStr = strconv.FormatFloat(memoryTotal/(1024*1024*1024), 'f', 2, 64) + " GB"
}
if memoryUsage < 1024*1024*1024 {
memoryUsageStr = strconv.FormatFloat(memoryUsage/(1024*1024), 'f', 2, 64) + " MB"
} else {
memoryUsageStr = strconv.FormatFloat(memoryUsage/(1024*1024*1024), 'f', 2, 64) + " GB"
}
if runtime.GOOS != "windows" {
swapTotal := float64(mv.SwapTotal)
swapUsage := float64(mv.SwapTotal - mv.SwapFree)
if swapTotal != 0 {
if swapTotal < 1024*1024*1024 {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024), 'f', 2, 64) + " MB"
} else {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024*1024), 'f', 2, 64) + " GB"
}
if swapUsage < 1024*1024*1024 {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024), 'f', 2, 64) + " MB"
} else {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024*1024), 'f', 2, 64) + " GB"
}
}
}
}
if runtime.GOOS == "windows" {
// gopsutil 在 Windows 下不能正确取 swap
ms, err := mem.SwapMemory()
if err != nil {
println("mem.SwapMemory error:", err)
} else {
swapTotal := float64(ms.Total)
swapUsage := float64(ms.Used)
if swapTotal != 0 {
if swapTotal < 1024*1024*1024 {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024), 'f', 2, 64) + " MB"
} else {
swapTotalStr = strconv.FormatFloat(swapTotal/(1024*1024*1024), 'f', 2, 64) + " GB"
}
if swapUsage < 1024*1024*1024 {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024), 'f', 2, 64) + " MB"
} else {
swapUsageStr = strconv.FormatFloat(swapUsage/(1024*1024*1024), 'f', 2, 64) + " GB"
}
}
}
}
virtioBalloon, err := os.ReadFile("/proc/modules")
if err == nil {
if strings.Contains(string(virtioBalloon), "virtio_balloon") {
virtioBalloonStatus = "✔️ Enabled"
} else {
virtioBalloonStatus = ""
}
} else {
virtioBalloonStatus = ""
}
ksmStatus, err := os.ReadFile("/sys/kernel/mm/ksm/run")
if err == nil {
if strings.Contains(string(ksmStatus), "1") {
KernelSamepageMerging = "✔️ Enabled"
} else {
KernelSamepageMerging = ""
}
} else {
KernelSamepageMerging = ""
}
return memoryTotalStr, memoryUsageStr, swapTotalStr, swapUsageStr, virtioBalloonStatus, KernelSamepageMerging
}

52
system/model/model.go Normal file
View File

@@ -0,0 +1,52 @@
package model
type CpuInfo struct {
CpuModel string
CpuCores string
CpuCache string
CpuAesNi string
CpuVAH string
}
type MemoryInfo struct {
MemoryUsage string
MemoryTotal string
SwapUsage string
SwapTotal string
}
type DiskInfo struct {
DiskUsage string
DiskTotal string
BootPath string
}
type SystemInfo struct {
CpuInfo
MemoryInfo
DiskInfo
Platform string // 系统名字 Distro1
PlatformVersion string // 系统版本 Distro2
Kernel string // 系统内核
Arch string //
Uptime string // 正常运行时间
VmType string // 虚拟化架构
Load string // load1 load2 load3
NatType string // stun
VirtioBalloon string // 气球驱动
KSM string // 内存合并
TcpAccelerationMethod string // TCP拥塞控制
}
type Win32_Processor struct {
L2CacheSize uint32
L3CacheSize uint32
}
type Win32_ComputerSystem struct {
SystemType string
}
type Win32_OperatingSystem struct {
BuildType string
}

75
system/system.go Normal file
View File

@@ -0,0 +1,75 @@
package system
import (
"fmt"
"github.com/oneclickvirt/basics/system/model"
"strconv"
)
var (
expectDiskFsTypes = []string{
"apfs", "ext4", "ext3", "ext2", "f2fs", "reiserfs", "jfs", "btrfs",
"fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs", "fuse.rclone",
}
cpuType string
)
// GetHost 获取主机硬件信息
func GetHost() *model.SystemInfo {
var ret = &model.SystemInfo{}
// 系统信息查询
cpuType, ret.Uptime, ret.Platform, ret.Kernel, ret.Arch, ret.VmType, ret.NatType, _ = getHostInfo()
// CPU信息查询
ret, _ = getCpuInfo(ret, cpuType)
// 硬盘信息查询
ret.DiskTotal, ret.DiskUsage, ret.BootPath, _ = getDiskInfo()
// 内存信息查询
ret.MemoryTotal, ret.MemoryUsage, ret.SwapTotal, ret.SwapUsage, ret.VirtioBalloon, ret.KSM = getMemoryInfo()
// 获取负载信息
load1, load5, load15, err := getSystemLoad()
if err != nil {
load1, load5, load15 = 0, 0, 0
}
ret.Load = strconv.FormatFloat(load1, 'f', 2, 64) + " / " +
strconv.FormatFloat(load5, 'f', 2, 64) + " / " +
strconv.FormatFloat(load15, 'f', 2, 64)
// 获取TCP控制算法
ret.TcpAccelerationMethod = getTCPAccelerateStatus()
return ret
}
func GetSystemInfo() {
ret := GetHost()
fmt.Println("Cpu Model :", ret.CpuModel)
fmt.Println("Cpu Cores :", ret.CpuCores)
if ret.CpuCache != "" {
fmt.Println("Cpu Cache :", ret.CpuCache)
}
fmt.Println("AES-NI :", ret.CpuAesNi)
fmt.Println("VM-x/AMD-V/Hyper-V :", ret.CpuVAH)
fmt.Println("RAM :", ret.MemoryUsage+" / "+ret.MemoryTotal)
if ret.VirtioBalloon != "" {
fmt.Println("Virtio Balloon :", ret.VirtioBalloon)
}
if ret.KSM != "" {
fmt.Println("KSM :", ret.KSM)
}
if ret.SwapTotal == "" && ret.SwapUsage == "" {
fmt.Println("Swap : [ no swap partition or swap file detected ]")
} else if ret.SwapTotal != "" && ret.SwapUsage != "" {
fmt.Println("Swap :", ret.SwapUsage+" / "+ret.SwapTotal)
}
fmt.Println("Disk :", ret.DiskUsage+" / "+ret.DiskTotal)
fmt.Println("Boot Path :", ret.BootPath)
fmt.Println("OS Release :", ret.Platform+" ["+ret.Arch+"] ")
if ret.Kernel != "" {
fmt.Println("Kernel :", ret.Kernel)
}
fmt.Println("Uptime :", ret.Uptime)
fmt.Println("Load :", ret.Load)
fmt.Println("VM Type :", ret.VmType)
fmt.Println("NAT Type :", ret.NatType)
if ret.TcpAccelerationMethod != "" {
fmt.Println("Tcp Accelerate :", ret.TcpAccelerationMethod)
}
}

9
system/system_test.go Normal file
View File

@@ -0,0 +1,9 @@
package system
import (
"testing"
)
func TestGetSystemInfo(t *testing.T) {
GetSystemInfo()
}

View File

@@ -0,0 +1,19 @@
package system
import (
"bytes"
"os/exec"
)
// getTCPAccelerateStatus 查询TCP控制算法
func getTCPAccelerateStatus() string {
cmd := exec.Command("sysctl", "-n", "net.ipv4.tcp_congestion_control")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return ""
} else {
return out.String()
}
}

View File

@@ -0,0 +1,6 @@
package system
// getTCPAccelerateStatus 查询TCP控制算法
func getTCPAccelerateStatus() string {
return ""
}