Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/network_info_plus/network_info_plus/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.1.0

- macOS: Add submask, broadcast, gateway info

## 2.0.2

- Upgrade Android compile SDK version
Expand Down
4 changes: 2 additions & 2 deletions packages/network_info_plus/network_info_plus/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: network_info_plus
description: Flutter plugin for discovering information (e.g. WiFi details) of the network.
version: 2.0.2
version: 2.1.0
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/

Expand All @@ -27,7 +27,7 @@ dependencies:
meta: ^1.3.0
network_info_plus_platform_interface: ^1.1.0
network_info_plus_linux: ^1.0.0
network_info_plus_macos: ^1.1.0
network_info_plus_macos: ^1.3.0
network_info_plus_windows: ^1.0.0
network_info_plus_web: ^1.0.0

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.3.0

- Add submask, broadcast, gateway info

## 1.2.0

- Remove `Reachability` dependency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,52 +39,125 @@ public class NetworkInfoPlusPlugin: NSObject, FlutterPlugin {
case "wifiBSSID":
result(cwinterface?.bssid())
case "wifiIPAddress":
result(getWiFiAddress(family: AF_INET))
result(getWifiAddress(family: AF_INET))
case "wifiIPv6Address":
result(getWiFiAddress(family: AF_INET6))
result(getWifiAddress(family: AF_INET6))
case "wifiSubmask":
result("")
result(getWifiSubmask())
case "wifiBroadcast":
result("")
result(getWifiBroadcast())
case "wifiGatewayAddress":
result("")
result(getDefaultGateway())
default:
result(FlutterMethodNotImplemented)
}
}
}

// Return IP address of WiFi interface (en0) as a String, or `nil`
func getWiFiAddress(family: Int32) -> String? {
var address : String?

// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }

// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee

// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(family) {

// Check interface name:
let name = String(cString: interface.ifa_name)
if name == "en0" {

// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
public func getWifiAddress(family: Int32) -> String? {
return withWifiInterface(family: family) { descriptionForAddress($0.pointee.ifa_addr) }
}

public func getWifiSubmask() -> String? {
return withWifiInterface(family: AF_INET) { descriptionForAddress($0.pointee.ifa_netmask) }
}

public func getWifiBroadcast() -> String? {
return withWifiInterface(family: AF_INET) { descriptionForAddress($0.pointee.ifa_dstaddr) }
}

public func getDefaultGateway() -> String? {
var mib : [Int32] = [CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY];
var l : Int = 0
guard sysctl(&mib, UInt32(mib.count), nil, &l, nil, 0) == 0 else { return nil }

var buf = [UInt8](repeating: 0, count: l)
guard sysctl(&mib, UInt32(mib.count), &buf, &l, nil, 0) == 0 else { return nil }

return buf.withUnsafeBytes { buf in
var result : String?

var sa_tab = [UnsafePointer<sockaddr>?](repeating: nil, count: Int(RTAX_MAX))

var p = buf.baseAddress!
while p < buf.baseAddress! + l {
let rt = p.bindMemory(to: rt_msghdr.self, capacity: 1)
var sa = (UnsafeRawPointer(rt) + Int(MemoryLayout<rt_msghdr>.stride)).bindMemory(to: sockaddr.self, capacity: 1)

for i in 0..<Int(RTAX_MAX) {
if rt.pointee.rtm_addrs & (1 << i) != 0 {
sa_tab[i] = sa
sa = (UnsafeRawPointer(sa) + roundup(Int(sa.pointee.sa_len))).bindMemory(to: sockaddr.self, capacity: 1)
} else {
sa_tab[i] = nil
}
}

if rt.pointee.rtm_addrs & (RTA_DST | RTA_GATEWAY) == (RTA_DST | RTA_GATEWAY),
let sa_dst = sa_tab[Int(RTAX_DST)], let sa_gateway = sa_tab[Int(RTAX_GATEWAY)],
sa_dst.pointee.sa_family == AF_INET && sa_gateway.pointee.sa_family == AF_INET {

var ifname = [CChar](repeating: 0, count: 128)
if_indextoname(UInt32(rt.pointee.rtm_index), &ifname)
if String(cString: ifname) == "en0" {
result = descriptionForAddress(sa_gateway)
}
}

p += Int(rt.pointee.rtm_msglen)
}

return result
}
}
}

/// Calls the given closure with a pointer to Wi-Fi interface (`en0`). For
/// compatibility reasons it can be called multiple times.
///
/// - parameter family: One of `AF_INET` or `AF_INET6`
/// - parameter body: A closure with `UnsafePointer<ifaddrs>` parameter that
/// points to the found Wi-Fi interface. The argument is valid only for the
/// duration of the closure's execution.
/// - returns: The result of last call to `body` or `nil` if there was no `en0`
/// interface found.
func withWifiInterface<R>(family: Int32, body: (UnsafePointer<ifaddrs>) throws -> R) rethrows -> R? {
var result : R?

// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }

defer { freeifaddrs(ifaddr) }

// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee

// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(family) {

// Check interface name:
let name = String(cString: interface.ifa_name)
if name == "en0" {

result = try body(ifptr)
}
}
freeifaddrs(ifaddr)
}

return result
}

private func descriptionForAddress(_ addr : UnsafePointer<sockaddr>) -> String{
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(addr, socklen_t(addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
return String(cString: hostname)
}

return address
private func roundup(_ a: Int) -> Int {
return a > 0 ? (1 + ((a - 1) | (MemoryLayout<CLong>.stride - 1))) : MemoryLayout<CLong>.stride
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: network_info_plus_macos
description: macOS implementation of the network_info_plus plugin.
version: 1.2.0
version: 1.3.0
homepage: https://plus.fluttercommunity.dev/
repository: https://github.com/fluttercommunity/plus_plugins/tree/main/packages/

Expand Down