mirror of
https://github.com/anotherhadi/settuings.git
synced 2026-10-05 16:18:24 +02:00
123 lines
3.5 KiB
Go
123 lines
3.5 KiB
Go
package network
|
|
|
|
import "strings"
|
|
|
|
// Device is one row of `nmcli device status`.
|
|
type Device struct {
|
|
Name string
|
|
Type string // e.g. "wifi", "ethernet", "wireguard", "loopback"
|
|
State string // e.g. "connected", "disconnected", "unavailable"
|
|
Connection string // active connection profile name, empty if none
|
|
}
|
|
|
|
func (d Device) Connected() bool {
|
|
return strings.HasPrefix(d.State, "connected")
|
|
}
|
|
|
|
// ListDevices returns every network device known to NetworkManager.
|
|
func ListDevices() ([]Device, error) {
|
|
rows, err := runTerse("DEVICE,TYPE,STATE,CONNECTION", "device", "status")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
devices := make([]Device, 0, len(rows))
|
|
for _, row := range rows {
|
|
devices = append(devices, Device{
|
|
Name: field(row, 0),
|
|
Type: field(row, 1),
|
|
State: field(row, 2),
|
|
Connection: field(row, 3),
|
|
})
|
|
}
|
|
return devices, nil
|
|
}
|
|
|
|
// DeviceConnect asks NetworkManager to bring a device up using whichever
|
|
// saved connection profile fits it best. Unlike VPNUp (which reactivates a
|
|
// specific, already-known connection by name), this works even right after
|
|
// a disconnect, when `device status` no longer reports which connection
|
|
// profile was last active on that device.
|
|
func DeviceConnect(device string) error {
|
|
_, err := run("device", "connect", device)
|
|
return err
|
|
}
|
|
|
|
// DeviceIP4 returns the device's primary private IPv4 address without its
|
|
// CIDR suffix (e.g. "192.168.1.54"), or "" if the device has none.
|
|
func DeviceIP4(device string) (string, error) {
|
|
out, err := getField("IP4.ADDRESS", "device", "show", device)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if out == "" {
|
|
return "", nil
|
|
}
|
|
// nmcli -g can return multiple addresses newline-separated; keep the first.
|
|
if i := strings.IndexByte(out, '\n'); i >= 0 {
|
|
out = out[:i]
|
|
}
|
|
if i := strings.IndexByte(out, '/'); i >= 0 {
|
|
out = out[:i]
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// DeviceDetail holds everything settuings shows on the "network info" screen
|
|
// for a connected device: addressing, gateway, DNS and hardware details.
|
|
type DeviceDetail struct {
|
|
HWAddr string
|
|
MTU string
|
|
IPv4 string // address + CIDR, e.g. "192.168.1.54/24"
|
|
Gateway4 string
|
|
DNS4 []string
|
|
IPv6 []string
|
|
Gateway6 string
|
|
DNS6 []string
|
|
}
|
|
|
|
// DeviceDetails fetches full addressing/hardware info for device via
|
|
// `nmcli device show`. Unlike the tabular nmcli commands elsewhere in this
|
|
// package, `device show` prints one "KEY:VALUE" line per property (with
|
|
// "KEY[n]" for multi-valued ones) and does not escape colons inside values,
|
|
// so it's parsed differently from runTerse.
|
|
func DeviceDetails(device string) (DeviceDetail, error) {
|
|
out, err := run("-t", "-f",
|
|
"GENERAL.HWADDR,GENERAL.MTU,IP4.ADDRESS,IP4.GATEWAY,IP4.DNS,IP6.ADDRESS,IP6.GATEWAY,IP6.DNS",
|
|
"device", "show", device)
|
|
if err != nil {
|
|
return DeviceDetail{}, err
|
|
}
|
|
|
|
var d DeviceDetail
|
|
for _, line := range strings.Split(strings.TrimRight(out, "\n"), "\n") {
|
|
key, value, ok := strings.Cut(line, ":")
|
|
if !ok {
|
|
continue
|
|
}
|
|
if i := strings.IndexByte(key, '['); i >= 0 {
|
|
key = key[:i] // strip the "[n]" multi-value index
|
|
}
|
|
switch key {
|
|
case "GENERAL.HWADDR":
|
|
d.HWAddr = value
|
|
case "GENERAL.MTU":
|
|
d.MTU = value
|
|
case "IP4.ADDRESS":
|
|
if d.IPv4 == "" {
|
|
d.IPv4 = value
|
|
}
|
|
case "IP4.GATEWAY":
|
|
d.Gateway4 = value
|
|
case "IP4.DNS":
|
|
d.DNS4 = append(d.DNS4, value)
|
|
case "IP6.ADDRESS":
|
|
d.IPv6 = append(d.IPv6, value)
|
|
case "IP6.GATEWAY":
|
|
d.Gateway6 = value
|
|
case "IP6.DNS":
|
|
d.DNS6 = append(d.DNS6, value)
|
|
}
|
|
}
|
|
return d, nil
|
|
}
|