mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-05 08:36:37 +00:00
add disk encryption check
This commit is contained in:
22
client/system/disk_encryption.go
Normal file
22
client/system/disk_encryption.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package system
|
||||
|
||||
// DiskEncryptionVolume represents encryption status of a single volume.
|
||||
type DiskEncryptionVolume struct {
|
||||
Path string
|
||||
Encrypted bool
|
||||
}
|
||||
|
||||
// DiskEncryptionInfo holds disk encryption detection results.
|
||||
type DiskEncryptionInfo struct {
|
||||
Volumes []DiskEncryptionVolume
|
||||
}
|
||||
|
||||
// IsEncrypted returns true if the volume at the given path is encrypted.
|
||||
func (d DiskEncryptionInfo) IsEncrypted(path string) bool {
|
||||
for _, v := range d.Volumes {
|
||||
if v.Path == path {
|
||||
return v.Encrypted
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
35
client/system/disk_encryption_darwin.go
Normal file
35
client/system/disk_encryption_darwin.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build darwin && !ios
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// detectDiskEncryption detects FileVault encryption status on macOS.
|
||||
func detectDiskEncryption(ctx context.Context) DiskEncryptionInfo {
|
||||
info := DiskEncryptionInfo{}
|
||||
|
||||
cmdCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(cmdCtx, "fdesetup", "status")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Debugf("execute fdesetup: %v", err)
|
||||
return info
|
||||
}
|
||||
|
||||
encrypted := strings.Contains(string(output), "FileVault is On")
|
||||
info.Volumes = append(info.Volumes, DiskEncryptionVolume{
|
||||
Path: "/",
|
||||
Encrypted: encrypted,
|
||||
})
|
||||
|
||||
return info
|
||||
}
|
||||
98
client/system/disk_encryption_linux.go
Normal file
98
client/system/disk_encryption_linux.go
Normal file
@@ -0,0 +1,98 @@
|
||||
//go:build linux && !android
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// detectDiskEncryption detects LUKS encryption status on Linux by reading sysfs.
|
||||
func detectDiskEncryption(ctx context.Context) DiskEncryptionInfo {
|
||||
info := DiskEncryptionInfo{}
|
||||
|
||||
encryptedDevices := findEncryptedDevices()
|
||||
mountPoints := parseMounts(encryptedDevices)
|
||||
|
||||
info.Volumes = mountPoints
|
||||
return info
|
||||
}
|
||||
|
||||
// findEncryptedDevices scans /sys/block for dm-crypt (LUKS) encrypted devices.
|
||||
func findEncryptedDevices() map[string]bool {
|
||||
encryptedDevices := make(map[string]bool)
|
||||
|
||||
sysBlock := "/sys/block"
|
||||
entries, err := os.ReadDir(sysBlock)
|
||||
if err != nil {
|
||||
log.Debugf("read /sys/block: %v", err)
|
||||
return encryptedDevices
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
dmUuidPath := filepath.Join(sysBlock, entry.Name(), "dm", "uuid")
|
||||
data, err := os.ReadFile(dmUuidPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
uuid := strings.TrimSpace(string(data))
|
||||
if strings.HasPrefix(uuid, "CRYPT-") {
|
||||
dmNamePath := filepath.Join(sysBlock, entry.Name(), "dm", "name")
|
||||
if nameData, err := os.ReadFile(dmNamePath); err == nil {
|
||||
dmName := strings.TrimSpace(string(nameData))
|
||||
encryptedDevices["/dev/mapper/"+dmName] = true
|
||||
}
|
||||
encryptedDevices["/dev/"+entry.Name()] = true
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedDevices
|
||||
}
|
||||
|
||||
// parseMounts reads /proc/mounts and maps devices to mount points with encryption status.
|
||||
func parseMounts(encryptedDevices map[string]bool) []DiskEncryptionVolume {
|
||||
var volumes []DiskEncryptionVolume
|
||||
|
||||
mountsFile, err := os.Open("/proc/mounts")
|
||||
if err != nil {
|
||||
log.Debugf("open /proc/mounts: %v", err)
|
||||
return volumes
|
||||
}
|
||||
defer func() {
|
||||
if err := mountsFile.Close(); err != nil {
|
||||
log.Debugf("close /proc/mounts: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
scanner := bufio.NewScanner(mountsFile)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
device, mountPoint := fields[0], fields[1]
|
||||
|
||||
encrypted := encryptedDevices[device]
|
||||
|
||||
if !encrypted && strings.HasPrefix(device, "/dev/mapper/") {
|
||||
for encDev := range encryptedDevices {
|
||||
if device == encDev {
|
||||
encrypted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volumes = append(volumes, DiskEncryptionVolume{
|
||||
Path: mountPoint,
|
||||
Encrypted: encrypted,
|
||||
})
|
||||
}
|
||||
|
||||
return volumes
|
||||
}
|
||||
10
client/system/disk_encryption_stub.go
Normal file
10
client/system/disk_encryption_stub.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build android || ios || freebsd || js
|
||||
|
||||
package system
|
||||
|
||||
import "context"
|
||||
|
||||
// detectDiskEncryption is a stub for unsupported platforms.
|
||||
func detectDiskEncryption(_ context.Context) DiskEncryptionInfo {
|
||||
return DiskEncryptionInfo{}
|
||||
}
|
||||
41
client/system/disk_encryption_windows.go
Normal file
41
client/system/disk_encryption_windows.go
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/yusufpapurcu/wmi"
|
||||
)
|
||||
|
||||
// Win32EncryptableVolume represents the WMI class for BitLocker status.
|
||||
type Win32EncryptableVolume struct {
|
||||
DriveLetter string
|
||||
ProtectionStatus uint32
|
||||
}
|
||||
|
||||
// detectDiskEncryption detects BitLocker encryption status on Windows via WMI.
|
||||
func detectDiskEncryption(_ context.Context) DiskEncryptionInfo {
|
||||
info := DiskEncryptionInfo{}
|
||||
|
||||
var volumes []Win32EncryptableVolume
|
||||
query := "SELECT DriveLetter, ProtectionStatus FROM Win32_EncryptableVolume"
|
||||
|
||||
err := wmi.QueryNamespace(query, &volumes, `root\CIMV2\Security\MicrosoftVolumeEncryption`)
|
||||
if err != nil {
|
||||
log.Debugf("query BitLocker status: %v", err)
|
||||
return info
|
||||
}
|
||||
|
||||
for _, vol := range volumes {
|
||||
driveLetter := strings.TrimSuffix(vol.DriveLetter, "\\")
|
||||
info.Volumes = append(info.Volumes, DiskEncryptionVolume{
|
||||
Path: driveLetter,
|
||||
Encrypted: vol.ProtectionStatus == 1,
|
||||
})
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
@@ -59,6 +59,7 @@ type Info struct {
|
||||
SystemManufacturer string
|
||||
Environment Environment
|
||||
Files []File // for posture checks
|
||||
DiskEncryption DiskEncryptionInfo
|
||||
|
||||
RosenpassEnabled bool
|
||||
RosenpassPermissive bool
|
||||
|
||||
@@ -44,6 +44,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
SystemSerialNumber: serial(),
|
||||
SystemProductName: productModel(),
|
||||
SystemManufacturer: productManufacturer(),
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
|
||||
return gio
|
||||
|
||||
@@ -62,6 +62,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
SystemProductName: si.SystemProductName,
|
||||
SystemManufacturer: si.SystemManufacturer,
|
||||
Environment: si.Environment,
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
|
||||
systemHostname, _ := os.Hostname()
|
||||
|
||||
@@ -55,6 +55,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
UIVersion: extractUserAgent(ctx),
|
||||
KernelVersion: osInfo[1],
|
||||
Environment: env,
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
sysName := extractOsName(ctx, "sysName")
|
||||
swVersion := extractOsVersion(ctx, "swVersion")
|
||||
|
||||
gio := &Info{Kernel: sysName, OSVersion: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU(), KernelVersion: swVersion}
|
||||
gio := &Info{Kernel: sysName, OSVersion: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU(), KernelVersion: swVersion, DiskEncryption: detectDiskEncryption(ctx)}
|
||||
gio.Hostname = extractDeviceName(ctx, "hostname")
|
||||
gio.NetbirdVersion = version.NetbirdVersion()
|
||||
gio.UIVersion = extractUserAgent(ctx)
|
||||
|
||||
@@ -15,7 +15,7 @@ func UpdateStaticInfoAsync() {
|
||||
}
|
||||
|
||||
// GetInfo retrieves system information for WASM environment
|
||||
func GetInfo(_ context.Context) *Info {
|
||||
func GetInfo(ctx context.Context) *Info {
|
||||
info := &Info{
|
||||
GoOS: runtime.GOOS,
|
||||
Kernel: runtime.GOARCH,
|
||||
@@ -25,6 +25,7 @@ func GetInfo(_ context.Context) *Info {
|
||||
Hostname: "wasm-client",
|
||||
CPUs: runtime.NumCPU(),
|
||||
NetbirdVersion: version.NetbirdVersion(),
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
|
||||
collectBrowserInfo(info)
|
||||
|
||||
@@ -73,6 +73,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
SystemProductName: si.SystemProductName,
|
||||
SystemManufacturer: si.SystemManufacturer,
|
||||
Environment: si.Environment,
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
|
||||
return gio
|
||||
|
||||
@@ -35,6 +35,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
SystemProductName: si.SystemProductName,
|
||||
SystemManufacturer: si.SystemManufacturer,
|
||||
Environment: si.Environment,
|
||||
DiskEncryption: detectDiskEncryption(ctx),
|
||||
}
|
||||
|
||||
addrs, err := networkAddresses()
|
||||
|
||||
Reference in New Issue
Block a user