diff --git a/client/system/chassis.go b/client/system/chassis.go new file mode 100644 index 000000000..d889c2549 --- /dev/null +++ b/client/system/chassis.go @@ -0,0 +1,119 @@ +package system + +const ( + ChassisTypeOther uint = 0x01 // Other + ChassisTypeUnknown uint = 0x02 // Unknown + ChassisTypeDesktop uint = 0x03 // Desktop + ChassisTypeLowProfileDesktop uint = 0x04 // Low Profile Desktop + ChassisTypePizzaBox uint = 0x05 // Pizza Box + ChassisTypeMiniTower uint = 0x06 // Mini Tower + ChassisTypeTower uint = 0x07 // Tower + ChassisTypePortable uint = 0x08 // Portable + ChassisTypeLaptop uint = 0x09 // Laptop + ChassisTypeNotebook uint = 0x0a // Notebook + ChassisTypeHandHeld uint = 0x0b // Hand Held + ChassisTypeDockingStation uint = 0x0c // Docking Station + ChassisTypeAllInOne uint = 0x0d // All in One + ChassisTypeSubNotebook uint = 0x0e // Sub Notebook + ChassisTypeSpacesaving uint = 0x0f // Space-saving + ChassisTypeLunchBox uint = 0x10 // Lunch Box + ChassisTypeMainServerChassis uint = 0x11 // Main Server Chassis + ChassisTypeExpansionChassis uint = 0x12 // Expansion Chassis + ChassisTypeSubChassis uint = 0x13 // SubChassis + ChassisTypeBusExpansionChassis uint = 0x14 // Bus Expansion Chassis + ChassisTypePeripheralChassis uint = 0x15 // Peripheral Chassis + ChassisTypeRAIDChassis uint = 0x16 // RAID Chassis + ChassisTypeRackMountChassis uint = 0x17 // Rack Mount Chassis + ChassisTypeSealedcasePC uint = 0x18 // Sealed-case PC + ChassisTypeMultisystemChassis uint = 0x19 // Multi-system chassis + ChassisTypeCompactPCI uint = 0x1a // Compact PCI + ChassisTypeAdvancedTCA uint = 0x1b // Advanced TCA + ChassisTypeBlade uint = 0x1c // Blade + ChassisTypeBladeChassis uint = 0x1d // Blade Chassis + ChassisTypeTablet uint = 0x1e // Tablet + ChassisTypeConvertible uint = 0x1f // Convertible + ChassisTypeDetachable uint = 0x20 // Detachable + ChassisTypeIoTGateway uint = 0x21 // IoT Gateway + ChassisTypeEmbeddedPC uint = 0x22 // Embedded PC + ChassisTypeMiniPC uint = 0x23 // Mini PC + ChassisTypeStickPC uint = 0x24 // Stick PC +) + +func chassisTypeDesc(id uint) string { + switch id { + case ChassisTypeOther: + return "Other" + case ChassisTypeUnknown: + return "Unknown" + case ChassisTypeDesktop: + return "Desktop" + case ChassisTypeLowProfileDesktop: + return "Low Profile Desktop" + case ChassisTypePizzaBox: + return "Pizza Box" + case ChassisTypeMiniTower: + return "Mini Tower" + case ChassisTypeTower: + return "Tower" + case ChassisTypePortable: + return "Portable" + case ChassisTypeLaptop: + return "Laptop" + case ChassisTypeNotebook: + return "Notebook" + case ChassisTypeHandHeld: + return "Hand Held" + case ChassisTypeDockingStation: + return "Docking Station" + case ChassisTypeAllInOne: + return "All In One" + case ChassisTypeSubNotebook: + return "Sub Notebook" + case ChassisTypeSpacesaving: + return "Space-saving" + case ChassisTypeLunchBox: + return "Lunch Box" + case ChassisTypeMainServerChassis: + return "Main Server Chassis" + case ChassisTypeExpansionChassis: + return "Expansion Chassis" + case ChassisTypeSubChassis: + return "Sub Chassis" + case ChassisTypeBusExpansionChassis: + return "Bus Expansion Chassis" + case ChassisTypePeripheralChassis: + return "Peripheral Chassis" + case ChassisTypeRAIDChassis: + return "RAID Chassis" + case ChassisTypeRackMountChassis: + return "Rack Mount Chassis" + case ChassisTypeSealedcasePC: + return "Sealed-case PC" + case ChassisTypeMultisystemChassis: + return "Multi-system" + case ChassisTypeCompactPCI: + return "CompactPCI" + case ChassisTypeAdvancedTCA: + return "AdvancedTCA" + case ChassisTypeBlade: + return "Blade" + case ChassisTypeBladeChassis: + return "Blade Chassis" + case ChassisTypeTablet: + return "Tablet" + case ChassisTypeConvertible: + return "Convertible" + case ChassisTypeDetachable: + return "Detachable" + case ChassisTypeIoTGateway: + return "IoT Gateway" + case ChassisTypeEmbeddedPC: + return "Embedded PC" + case ChassisTypeMiniPC: + return "Mini PC" + case ChassisTypeStickPC: + return "Stick PC" + default: + return "Unknown" + } +} diff --git a/client/system/info.go b/client/system/info.go index 2d5b7192e..13c83926b 100644 --- a/client/system/info.go +++ b/client/system/info.go @@ -31,6 +31,27 @@ type Info struct { CPUs int WiretrusteeVersion string UIVersion string + + BiosManufacturer string + BiosVersion string + ChassisType uint + ChassisTypeDesc string + ConnectionIp string + ConnectionMacAddress string + CPUSignature string + DefaultGatewayIp string + ExternalIp string + LastReboot string + LocalIp string + MacAddress string + KernelMajorVersion string + KernelMinorVersion string + OSBuild string + OSProductName string + ProductTypeDesc string + SerialNumber string + SystemManufacturer string + SystemProductName string } // extractUserAgent extracts Netbird's agent (client) name and version from the outgoing context diff --git a/client/system/info_darwin.go b/client/system/info_darwin.go index 5ae2b4fc6..7470556f0 100644 --- a/client/system/info_darwin.go +++ b/client/system/info_darwin.go @@ -33,11 +33,23 @@ func GetInfo(ctx context.Context) *Info { log.Warnf("got an error while retrieving macOS version with sw_vers, error: %s. Using darwin version instead.\n", err) swVersion = []byte(release) } - gio := &Info{Kernel: sysName, OSVersion: strings.TrimSpace(string(swVersion)), Core: release, Platform: machine, OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} - systemHostname, _ := os.Hostname() - gio.Hostname = extractDeviceName(ctx, systemHostname) - gio.WiretrusteeVersion = version.NetbirdVersion() - gio.UIVersion = extractUserAgent(ctx) + systemHostname, _ := os.Hostname() + localAddr, macAddr := localAddresses() + gio := &Info{ + Kernel: sysName, + OSVersion: strings.TrimSpace(string(swVersion)), + Core: release, + Platform: machine, + OS: sysName, + GoOS: runtime.GOOS, + CPUs: runtime.NumCPU(), + Hostname: extractDeviceName(ctx, systemHostname), + WiretrusteeVersion: version.NetbirdVersion(), + UIVersion: extractUserAgent(ctx), + LastReboot: lastReboot(), + LocalIp: localAddr, + MacAddress: macAddr, + } return gio } diff --git a/client/system/info_linux.go b/client/system/info_linux.go index 21a4d482a..d03be4afd 100644 --- a/client/system/info_linux.go +++ b/client/system/info_linux.go @@ -13,6 +13,7 @@ import ( "time" log "github.com/sirupsen/logrus" + "github.com/zcalusic/sysinfo" "github.com/netbirdio/netbird/version" ) @@ -26,7 +27,7 @@ func GetInfo(ctx context.Context) *Info { } releaseInfo := _getReleaseInfo() - for strings.Contains(info, "broken pipe") { + for strings.Contains(releaseInfo, "broken pipe") { releaseInfo = _getReleaseInfo() time.Sleep(500 * time.Millisecond) } @@ -50,15 +51,51 @@ func GetInfo(ctx context.Context) *Info { if osName == "" { osName = osInfo[3] } - gio := &Info{Kernel: osInfo[0], Core: osInfo[1], Platform: osInfo[2], OS: osName, OSVersion: osVer, GoOS: runtime.GOOS, CPUs: runtime.NumCPU()} systemHostname, _ := os.Hostname() - gio.Hostname = extractDeviceName(ctx, systemHostname) - gio.WiretrusteeVersion = version.NetbirdVersion() - gio.UIVersion = extractUserAgent(ctx) + sysinfo := extendedInfo() + localAddr, macAddr := localAddresses() + gio := &Info{ + Kernel: osInfo[0], + Core: osInfo[1], + Platform: osInfo[2], + OS: osName, + OSVersion: osVer, + GoOS: runtime.GOOS, + CPUs: runtime.NumCPU(), + Hostname: extractDeviceName(ctx, systemHostname), + WiretrusteeVersion: version.NetbirdVersion(), + UIVersion: extractUserAgent(ctx), + BiosManufacturer: sysinfo.BIOS.Vendor, + BiosVersion: sysinfo.BIOS.Version, + ChassisType: sysinfo.Chassis.Type, + ChassisTypeDesc: chassisTypeDesc(sysinfo.Chassis.Type), // make no sense to send the string to the server + /* + ConnectionIp: "", // "10.145.236.123", + ConnectionMacAddress: "", // 52-54-00-1a-31-05" + CPUSignature: "", // "198339" + */ + LastReboot: lastReboot(), + LocalIp: localAddr, + MacAddress: macAddr, + /* + OSBuild: string // 22621 + OSProductName: string // "Windows 11 Home" + ProductTypeDesc: string // "Workstation" + SerialNumber: string // "MP1PKC2C"" + SystemProductName: string // "81ND", # how to get this? + */ + SystemManufacturer: sysinfo.Product.Vendor, // todo validate + } return gio } +func extendedInfo() sysinfo.SysInfo { + var si sysinfo.SysInfo + si.GetSysInfo() + return si +} + func _getInfo() string { cmd := exec.Command("uname", "-srio") cmd.Stdin = strings.NewReader("some") diff --git a/client/system/info_linux_test.go b/client/system/info_linux_test.go new file mode 100644 index 000000000..49413282a --- /dev/null +++ b/client/system/info_linux_test.go @@ -0,0 +1,13 @@ +package system + +import ( + "context" + "testing" + + log "github.com/sirupsen/logrus" +) + +func TestGetInfo(t *testing.T) { + info := GetInfo(context.Background()) + log.Infof("info: %+v", info) +} diff --git a/client/system/ip.go b/client/system/ip.go new file mode 100644 index 000000000..975934355 --- /dev/null +++ b/client/system/ip.go @@ -0,0 +1,42 @@ +package system + +import ( + "net" + + log "github.com/sirupsen/logrus" +) + +func localAddresses() (string, string) { + conn, err := net.Dial("udp", "8.8.8.8:53") + if err != nil { + log.Errorf("failed to check ip: %s", err) + return "", "" + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + ifaces, err := net.Interfaces() + if err != nil { + log.Errorf("failed to list interfaces: %s", err) + return "", "" + } + for _, i := range ifaces { + addrs, err := i.Addrs() + if err != nil { + log.Errorf("failed to list addresses: %s", err) + continue + } + + for _, addr := range addrs { + cidr, _, err := net.ParseCIDR(addr.String()) + if err != nil { + continue + } + + if localAddr.IP.String() == cidr.String() { + return addr.String(), i.HardwareAddr.String() + } + } + } + return "", "" +} diff --git a/client/system/reboot.go b/client/system/reboot.go new file mode 100644 index 000000000..545075653 --- /dev/null +++ b/client/system/reboot.go @@ -0,0 +1,17 @@ +package system + +import ( + "time" + + "github.com/shirou/gopsutil/host" + log "github.com/sirupsen/logrus" +) + +func lastReboot() string { + info, err := host.Info() + if err != nil { + log.Errorf("failed to get boot time: %s", err) + return "" + } + return time.Unix(int64(info.BootTime), 0).String() +} diff --git a/go.mod b/go.mod index 053aa0e3c..2e29149c5 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54 golang.org/x/crypto v0.14.0 - golang.org/x/sys v0.13.0 + golang.org/x/sys v0.15.0 golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 golang.zx2c4.com/wireguard/windows v0.5.3 @@ -64,10 +64,12 @@ require ( github.com/pion/transport/v3 v3.0.1 github.com/prometheus/client_golang v1.14.0 github.com/rs/xid v1.3.0 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.8.4 github.com/things-go/go-socks5 v0.0.4 github.com/yusufpapurcu/wmi v1.2.3 + github.com/zcalusic/sysinfo v1.0.2 go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel/exporters/prometheus v0.33.0 go.opentelemetry.io/otel/metric v0.33.0 @@ -143,6 +145,8 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yuin/goldmark v1.4.13 // indirect go.opencensus.io v0.24.0 // indirect diff --git a/go.sum b/go.sum index 175e34c94..5cff8b520 100644 --- a/go.sum +++ b/go.sum @@ -476,6 +476,8 @@ github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +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/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -519,6 +521,10 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/things-go/go-socks5 v0.0.4 h1:jMQjIc+qhD4z9cITOMnBiwo9dDmpGuXmBlkRFrl/qD0= github.com/things-go/go-socks5 v0.0.4/go.mod h1:sh4K6WHrmHZpjxLTCHyYtXYH8OUuD+yZun41NomR1IQ= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= @@ -537,6 +543,8 @@ github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc= +github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -755,8 +763,9 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=