Files

274 lines
6.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package host_info
import (
"agent-wdd/log"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"regexp"
"time"
)
// 能够联网,就大于这个数字 外网9 国内7 不能联网1 未知0
const InternetBaseLine = 1
// 定义响应数据结构体
type IPInfo struct {
IP string `json:"ip"`
City string `json:"city"`
Region string `json:"region"`
Country string `json:"country"`
Loc string `json:"loc"`
Org string `json:"org"`
Postal string `json:"postal"`
Timezone string `json:"timezone"`
}
// Gather 获取网络相关的信息
func (network *Network) Gather() {
log.Info("Gathering INFO => NETWORK !")
// 能够联网
network.Internet = CanConnectInternet()
// 获取公网的相关信息
network.Public = network.Public.GetPublicInfo()
//获取本机网卡相关的内容
network.Interfaces = GetInterfaces()
}
// GetInterfaces 获取本机网卡相关的内容
func GetInterfaces() []Interface {
interfaces := []Interface{}
// 获取所有网卡信息
netInterfaces, err := net.Interfaces()
// log.Info("all network interfaces: %v", netInterfaces)
if err != nil {
log.Error("获取网卡信息失败: %v", err)
return interfaces
}
for _, netInterface := range netInterfaces {
// 过滤掉没有地址的网卡
addrs, err := netInterface.Addrs()
if err != nil || len(addrs) == 0 {
continue
}
// 检查网卡名称是否有效
if !isValidNICName(netInterface.Name) {
continue
}
// 创建 Interface 对象
iface := Interface{
Name: netInterface.Name,
MAC: netInterface.HardwareAddr.String(),
MTU: netInterface.MTU,
}
// 获取 IPv4 和 IPv6 地址
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipNet.IP.To4() != nil {
iface.IPv4 = ipNet.IP.String()
} else if ipNet.IP.To16() != nil {
iface.IPv6 = ipNet.IP.String()
}
}
interfaces = append(interfaces, iface)
}
return interfaces
}
func (network *Network) SaveConfig() {
ConfigCache.Agent.Network = *network
SaveConfig()
}
// CanConnectInternet 判定主机能够上网 外网为9 国内为7 不能上网为1
func CanConnectInternet() int {
// 读取 config 文件,判定能否上网
internetCode := ConfigCache.Agent.Network.Internet
if internetCode == 0 {
// 没有相关的信息,需要重新判定
internetCode = judgeCanConnectInternet()
// 持久化保存
ConfigCache.Agent.Network.Internet = internetCode
}
return internetCode
}
// judgeCanConnectInternet 请求网址判定主机能否上网 请求 www.google.com 如果请求正常 返回9 如果超时三秒 请求baidu.com如果没有错误返回7 如果错误返回1
func judgeCanConnectInternet() int {
client := http.Client{
Timeout: 3 * time.Second,
}
results := make(chan int, 2)
go func() {
_, err := client.Get("https://www.google.com")
if err == nil {
results <- 9
} else {
results <- 1
}
}()
go func() {
_, err := client.Get("https://www.baidu.com")
if err == nil {
results <- 7
} else {
results <- 1
}
}()
maxResult := 1
for i := 0; i < 2; i++ {
result := <-results
if result > maxResult {
maxResult = result
}
}
return maxResult
}
// GetPublicInfo 获取服务器的公网信息
func (p PublicInfo) GetPublicInfo() PublicInfo {
// 无法联网, 假信息
fakePublicInfo := PublicInfo{
IPv4: "1.1.1.1",
IPv6: "2400::1",
Country: "CN",
City: "Shanghai",
ASN: "Wdd Inc",
Timezone: "Asia/Shanghai",
}
if CanConnectInternet() == InternetBaseLine {
// 持久化保存
ConfigCache.Agent.Network.Public = fakePublicInfo
return fakePublicInfo
}
// 可以联网
// 创建带有超时的HTTP客户端
client := &http.Client{
Timeout: 3 * time.Second,
}
// 创建新的请求对象
req, err := http.NewRequest("GET", "https://ipinfo.io", nil)
if err != nil {
log.Error("创建请求失败: %v", err)
return fakePublicInfo
}
// 设置请求头
req.Header.Add("Authorization", "Bearer 6ecb0db9bd8f19")
req.Header.Add("Accept", "application/json")
// 发送请求
resp, err := client.Do(req)
if err != nil {
log.Error("请求PublicInfo失败: %s", err.Error())
return fakePublicInfo
}
defer resp.Body.Close()
// 检查响应状态码
if resp.StatusCode != http.StatusOK {
log.Error("非200状态码: %d", resp.StatusCode)
}
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Error("读取响应失败: %v", err)
}
// 解析JSON数据
var info IPInfo
if err := json.Unmarshal(body, &info); err != nil {
log.Error("JSON解析失败: %v", err)
}
// 打印解析结果
// log.Info("IP信息:\n%+v\n", info)
// 保存信息
p.IPv4 = info.IP
p.ASN = info.Org
p.Country = info.Country
p.City = info.City
p.Timezone = info.Timezone
ConfigCache.Agent.Network.Public = p
return p
}
func isValidNICName(name string) bool {
// 定义传统命名规则正则表达式
// eth0, eth1, wlan0, wlan1 等
traditionalPattern := `^(eth|wlan)[0-9]+$`
// 定义现代命名规则正则表达式
// 支持 eno1, ens3, enp0s3, enx<MAC>, wlp2s0 等格式
modernPattern := `^(en|wl)(o[0-9]+|s[0-9]+|p[0-9]+s[0-9]+|x[0-9a-fA-F]{12})$`
// 编译正则表达式
traditionalRegex := regexp.MustCompile(traditionalPattern)
modernRegex := regexp.MustCompile(modernPattern)
// 检查是否匹配传统命名或现代命名规则
return traditionalRegex.MatchString(name) || modernRegex.MatchString(name)
}
func main() {
// 测试用例
testCases := []string{
"eth0", // 传统以太网命名
"wlan1", // 传统无线网卡命名
"eno1", // 板载网卡
"ens3", // 插槽网卡
"enp0s3", // PCI网卡
"enx0a1b2c3d4e5f", // 基于MAC地址的命名
"wlp2s0", // 无线PCI网卡
"eth", // 无效:缺少数字
"enp0", // 无效:不符合现代规则
"abc123", // 无效:完全不匹配
}
for _, tc := range testCases {
if isValidNICName(tc) {
fmt.Printf("%s: 有效网卡名称\n", tc)
} else {
fmt.Printf("%s: 无效网卡名称\n", tc)
}
}
}