github.com/simpleiot/simpleiot@v0.18.3/client/network-manager-device.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package client
     5  
     6  import (
     7  	"encoding/json"
     8  
     9  	nm "github.com/Wifx/gonetworkmanager/v2"
    10  )
    11  
    12  // NetworkManagerDevice is a device managed by NetworkManager
    13  type NetworkManagerDevice struct {
    14  	ID         string `node:"id"`
    15  	Parent     string `node:"parent"`
    16  	Path       string `point:"path"`
    17  	Interface  string `point:"interface"`
    18  	State      string `point:"state"`
    19  	DeviceType string `point:"deviceType"`
    20  	// ActiveConnectionID
    21  	IPv4Addresses   []IPv4Address `point:"ipv4Addresses"`
    22  	IPv4Netmasks    []IPv4Netmask `point:"ipv4Netmasks"`
    23  	IPv4Gateway     IPv4Address   `point:"ipv4Gateway"`
    24  	IPv4Nameservers []IPv4Address `point:"ipv4Nameservers"`
    25  	IPv6Addresses   []IPv6Address `point:"ipv6Addresses"`
    26  	IPv6Prefixes    []uint8       `point:"ipv6Prefixes"`
    27  	IPv6Gateway     IPv6Address   `point:"ipv6Gateway"`
    28  	IPv6Nameservers []IPv6Address `point:"ipv6Nameservers"`
    29  	HardwareAddress string        `point:"hardwareAddress"`
    30  	Managed         bool
    31  	// Wi-Fi specific properties
    32  	ActiveAccessPoint *AccessPoint `point:"activeAccessPoint"`
    33  	AccessPoints      []string     `point:"accessPoints"` // JSON-encoded strings
    34  }
    35  
    36  // ResolveDevice returns a NetworkManagerDevice from a NetworkManager Device
    37  func ResolveDevice(parent string, device nm.Device) (
    38  	dev NetworkManagerDevice, err error,
    39  ) {
    40  	dev.Parent = parent
    41  
    42  	// Read device info via D-Bus
    43  	dev.Path = string(device.GetPath())
    44  	dev.ID = dev.Path
    45  
    46  	dev.Interface, err = device.GetPropertyInterface()
    47  	if err != nil {
    48  		return dev, err
    49  	}
    50  	if dev.Interface != "" {
    51  		dev.ID = dev.Interface
    52  	}
    53  
    54  	ipIface, err := device.GetPropertyIpInterface()
    55  	if err != nil {
    56  		return dev, err
    57  	}
    58  	if ipIface != "" {
    59  		dev.ID = ipIface
    60  	}
    61  
    62  	state, err := device.GetPropertyState()
    63  	if err != nil {
    64  		return dev, err
    65  	}
    66  	dev.State = state.String()
    67  
    68  	// Populate IPv4 state
    69  	ipv4, err := device.GetPropertyIP4Config()
    70  	if err != nil {
    71  		return dev, err
    72  	}
    73  	if ipv4 != nil {
    74  		ip4Addresses, err := ipv4.GetPropertyAddressData()
    75  		if err != nil {
    76  			return dev, err
    77  		}
    78  		for _, addr := range ip4Addresses {
    79  			dev.IPv4Addresses = append(dev.IPv4Addresses,
    80  				IPv4Address(addr.Address),
    81  			)
    82  			dev.IPv4Netmasks = append(dev.IPv4Netmasks,
    83  				IPv4NetmaskPrefix(addr.Prefix),
    84  			)
    85  		}
    86  
    87  		gateway, err := ipv4.GetPropertyGateway()
    88  		if err != nil {
    89  			return dev, err
    90  		}
    91  		dev.IPv4Gateway = IPv4Address(gateway)
    92  
    93  		nameservers, err := ipv4.GetPropertyNameserverData()
    94  		if err != nil {
    95  			return dev, err
    96  		}
    97  		for _, addr := range nameservers {
    98  			if addr.Address != "" {
    99  				dev.IPv4Nameservers = append(dev.IPv4Nameservers,
   100  					IPv4Address(addr.Address),
   101  				)
   102  			}
   103  		}
   104  	}
   105  
   106  	ipv6, err := device.GetPropertyIP6Config()
   107  	if err != nil {
   108  		return dev, err
   109  	}
   110  	if ipv6 != nil {
   111  		// Populate IPv6 state
   112  		ip6Addresses, err := ipv6.GetPropertyAddressData()
   113  		if err != nil {
   114  			return dev, err
   115  		}
   116  		for _, addr := range ip6Addresses {
   117  			dev.IPv6Addresses = append(dev.IPv6Addresses, IPv6Address(addr.Address))
   118  			dev.IPv6Prefixes = append(dev.IPv6Prefixes, addr.Prefix)
   119  		}
   120  
   121  		gateway, err := ipv6.GetPropertyGateway()
   122  		if err != nil {
   123  			return dev, err
   124  		}
   125  		dev.IPv6Gateway = IPv6Address(gateway)
   126  
   127  		nameservers, err := ipv6.GetPropertyNameservers()
   128  		if err != nil {
   129  			return dev, err
   130  		}
   131  		for _, addr := range nameservers {
   132  			dev.IPv6Nameservers = append(dev.IPv6Nameservers,
   133  				NewIPv6Address(addr),
   134  			)
   135  		}
   136  	}
   137  
   138  	dev.Managed, err = device.GetPropertyManaged()
   139  	if err != nil {
   140  		return dev, err
   141  	}
   142  
   143  	deviceType, err := device.GetPropertyDeviceType()
   144  	if err != nil {
   145  		return dev, err
   146  	}
   147  	dev.DeviceType = deviceType.String()
   148  
   149  	if devHwAddr, ok := device.(interface {
   150  		GetPropertyHwAddress() (string, error)
   151  	}); ok {
   152  		dev.HardwareAddress, err = devHwAddr.GetPropertyHwAddress()
   153  		if err != nil {
   154  			return dev, err
   155  		}
   156  		if dev.HardwareAddress != "" && dev.HardwareAddress != "00:00:00:00:00:00" {
   157  			dev.ID = dev.HardwareAddress
   158  		}
   159  	}
   160  
   161  	// Add WiFi access point
   162  	if devAP, ok := device.(interface {
   163  		GetPropertyActiveAccessPoint() (nm.AccessPoint, error)
   164  	}); ok {
   165  		ap, err := devAP.GetPropertyActiveAccessPoint()
   166  		if err != nil {
   167  			return dev, err
   168  		}
   169  		if ap == nil {
   170  			dev.ActiveAccessPoint = nil
   171  		} else {
   172  			resolvedAP, err := ResolveAccessPoint(ap)
   173  			if err != nil {
   174  				return dev, err
   175  			}
   176  			dev.ActiveAccessPoint = &resolvedAP
   177  		}
   178  	}
   179  
   180  	// Add device type prefix to ID
   181  	dev.ID = deviceType.String() + "_" + dev.ID
   182  	return dev, err
   183  }
   184  
   185  // RescanTimeoutSeconds is the maximum number of seconds since LastScan that can
   186  // elapse before scanning for access points is requested
   187  const RescanTimeoutSeconds = 10
   188  
   189  // AccessPoint describes a network access point
   190  type AccessPoint struct {
   191  	SSID     string `json:"ssid"`
   192  	BSSID    string `json:"bssid"`
   193  	Strength uint8  `json:"strength"`
   194  	Flags    uint32 `json:"flags"`
   195  	WPAFlags uint32 `json:"wpaFlags"`
   196  	RSNFlags uint32 `json:"rsnFlags"`
   197  }
   198  
   199  // ResolveAccessPoint returns an AccessPoint from a NetworkManager AccessPoint
   200  func ResolveAccessPoint(ap nm.AccessPoint) (apOut AccessPoint, err error) {
   201  	ssid, err := ap.GetPropertySSID()
   202  	if err != nil {
   203  		return apOut, err
   204  	}
   205  	apOut.SSID = string(ssid)
   206  
   207  	apOut.BSSID, err = ap.GetPropertyHWAddress()
   208  	if err != nil {
   209  		return apOut, err
   210  	}
   211  
   212  	apOut.Strength, err = ap.GetPropertyStrength()
   213  	if err != nil {
   214  		return apOut, err
   215  	}
   216  
   217  	apOut.Flags, err = ap.GetPropertyFlags()
   218  	if err != nil {
   219  		return apOut, err
   220  	}
   221  
   222  	apOut.WPAFlags, err = ap.GetPropertyWPAFlags()
   223  	if err != nil {
   224  		return apOut, err
   225  	}
   226  
   227  	apOut.RSNFlags, err = ap.GetPropertyRSNFlags()
   228  	if err != nil {
   229  		return apOut, err
   230  	}
   231  
   232  	return apOut, err
   233  }
   234  
   235  // MarshallJSON returns a JSON representation of the AP
   236  func (ap AccessPoint) MarshallJSON() ([]byte, error) {
   237  	return json.Marshal(ap)
   238  }