在 Swift 中管理 return MAC 地址的 ifaddrs
Manage ifaddrs to return MAC addresses as well in Swift
我有以下代码可以成功检索连接到我的路由器的所有 IP。但我需要为每个 IP 获取 MAC 地址。
因此,不是将地址作为数组返回 [ips]
,而是作为字典返回 [ips:0000000, mac: 000000]
是否可以通过更改以下代码(来自How to get Ip address in swift)来实现?
func getIFAddresses() -> [String] {
print("GET IF ADDRESSSE")
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
print("getifaddrs\(getifaddrs)")
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
print("flags\(flags)")
print("addr\(addr)")
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
print("addr.sa_family\(addr.sa_family)")
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
print("hostname\(hostname)")
if (getnameinfo(
&addr, socklen_t(addr.sa_len),
&hostname,
socklen_t(hostname.count),
nil,
socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
print("freeifaddrs\(freeifaddrs)")
}
print("ADDRESSES \(addresses)")
return addresses
}
(Remark/clarification: 这是对问题 "Manage ifaddrs to return MAC addresses as well in Swift" 和 的回答"Is it possible to modify the code from How to get Ip address in swift to return the MAC addresses as well".
这不是 "retrieve all the IPs connected to my router" 的解决方案
这也在问题正文中提到。)
这里是引用代码的扩展 returns
本地(up 和 运行ning)接口为
(接口名称,IP 地址,MAC 地址) 元组的数组。
MAC 地址是从 AF_LINK
类型的接口中检索的
在接口列表中存储为 sockaddr_dl
结构。
这是一个可变长度结构,Swift 的严格类型系统使得一些指针变戏法成为必要。
重要提示: 此代码适用于 运行 Mac 计算机。
在 iOS 设备上获取 MAC 地址无效。
iOS 有意 returns "02:00:00:00:00:00" 作为硬件地址
对于出于隐私原因的所有界面,请参见示例
Trouble with MAC address in iOS 7.0.2.)
func getInterfaces() -> [(name : String, addr: String, mac : String)] {
var addresses = [(name : String, addr: String, mac : String)]()
var nameToMac = [ String : String ]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr.memory.ifa_next }
let flags = Int32(ptr.memory.ifa_flags)
let addr = ptr.memory.ifa_addr
if let name = String.fromCString(ptr.memory.ifa_name) {
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.memory.sa_family == UInt8(AF_LINK) {
// Get MAC address from sockaddr_dl structure and store in nameToMac dictionary:
let dl = UnsafePointer<sockaddr_dl>(ptr.memory.ifa_addr)
let lladdr = UnsafeBufferPointer(start: UnsafePointer<Int8>(dl) + 8 + Int(dl.memory.sdl_nlen),
count: Int(dl.memory.sdl_alen))
if lladdr.count == 6 {
nameToMac[name] = lladdr.map { String(format:"%02hhx", [=10=])}.joinWithSeparator(":")
}
}
if addr.memory.sa_family == UInt8(AF_INET) || addr.memory.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(addr, socklen_t(addr.memory.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append( (name: name, addr: address, mac : "") )
}
}
}
}
}
}
freeifaddrs(ifaddr)
}
// Now add the mac address to the tuples:
for (i, addr) in addresses.enumerate() {
if let mac = nameToMac[addr.name] {
addresses[i] = (name: addr.name, addr: addr.addr, mac : mac)
}
}
return addresses
}
您必须添加
#include <ifaddrs.h>
#include <net/if_dl.h>
到桥接头文件进行编译。
用法示例:
for addr in getInterfaces() {
print(addr)
}
// ("en0", "fe80::1234:7fff:fe2e:8765%en0", "a9:55:6f:2e:57:78")
// ("en0", "192.168.2.108", "a9:55:6f:2e:57:78")
// ...
更新 Swift 3 (Xcode 8):
func getInterfaces() -> [(name : String, addr: String, mac : String)] {
var addresses = [(name : String, addr: String, mac : String)]()
var nameToMac = [ String: String ]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return [] }
guard let firstAddr = ifaddr else { return [] }
// For each interface ...
for ptr in sequence(first: firstAddr, next: { [=13=].pointee.ifa_next }) {
let flags = Int32(ptr.pointee.ifa_flags)
if let addr = ptr.pointee.ifa_addr {
let name = String(cString: ptr.pointee.ifa_name)
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
switch Int32(addr.pointee.sa_family) {
case AF_LINK:
// Get MAC address from sockaddr_dl structure and store in nameToMac dictionary:
addr.withMemoryRebound(to: sockaddr_dl.self, capacity: 1) { dl in
dl.withMemoryRebound(to: Int8.self, capacity: 8 + Int(dl.pointee.sdl_nlen + dl.pointee.sdl_alen)) {
let lladdr = UnsafeBufferPointer(start: [=13=] + 8 + Int(dl.pointee.sdl_nlen),
count: Int(dl.pointee.sdl_alen))
if lladdr.count == 6 {
nameToMac[name] = lladdr.map { String(format:"%02hhx", [=13=])}.joined(separator: ":")
}
}
}
case AF_INET, AF_INET6:
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(addr, socklen_t(addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
addresses.append( (name: name, addr: address, mac : "") )
}
default:
break
}
}
}
}
freeifaddrs(ifaddr)
// Now add the mac address to the tuples:
for (i, addr) in addresses.enumerated() {
if let mac = nameToMac[addr.name] {
addresses[i] = (name: addr.name, addr: addr.addr, mac : mac)
}
}
return addresses
}
如果要在框架内使用它,则必须添加一个包含此配置的 .modelmap 文件
module ifaddrs [system] [extern_c] {
header
"/Applications/Xcode_7.3.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/ifaddrs.h"
export *
}
module net [system] [extern_c] {
module types {
header "/usr/include/sys/types.h"
export *
}
module if_dl {
header
"/usr/include/net/if_dl.h"
export *
}
}
然后在您的 .swift 文件中
import ifaddrs
import net.if_dl
我有以下代码可以成功检索连接到我的路由器的所有 IP。但我需要为每个 IP 获取 MAC 地址。
因此,不是将地址作为数组返回 [ips]
,而是作为字典返回 [ips:0000000, mac: 000000]
是否可以通过更改以下代码(来自How to get Ip address in swift)来实现?
func getIFAddresses() -> [String] {
print("GET IF ADDRESSSE")
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
print("getifaddrs\(getifaddrs)")
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
print("flags\(flags)")
print("addr\(addr)")
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
print("addr.sa_family\(addr.sa_family)")
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
print("hostname\(hostname)")
if (getnameinfo(
&addr, socklen_t(addr.sa_len),
&hostname,
socklen_t(hostname.count),
nil,
socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
print("freeifaddrs\(freeifaddrs)")
}
print("ADDRESSES \(addresses)")
return addresses
}
(Remark/clarification: 这是对问题 "Manage ifaddrs to return MAC addresses as well in Swift" 和 的回答"Is it possible to modify the code from How to get Ip address in swift to return the MAC addresses as well". 这不是 "retrieve all the IPs connected to my router" 的解决方案 这也在问题正文中提到。)
这里是引用代码的扩展 returns
本地(up 和 运行ning)接口为
(接口名称,IP 地址,MAC 地址) 元组的数组。
MAC 地址是从 AF_LINK
类型的接口中检索的
在接口列表中存储为 sockaddr_dl
结构。
这是一个可变长度结构,Swift 的严格类型系统使得一些指针变戏法成为必要。
重要提示: 此代码适用于 运行 Mac 计算机。 在 iOS 设备上获取 MAC 地址无效。 iOS 有意 returns "02:00:00:00:00:00" 作为硬件地址 对于出于隐私原因的所有界面,请参见示例 Trouble with MAC address in iOS 7.0.2.)
func getInterfaces() -> [(name : String, addr: String, mac : String)] {
var addresses = [(name : String, addr: String, mac : String)]()
var nameToMac = [ String : String ]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr.memory.ifa_next }
let flags = Int32(ptr.memory.ifa_flags)
let addr = ptr.memory.ifa_addr
if let name = String.fromCString(ptr.memory.ifa_name) {
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.memory.sa_family == UInt8(AF_LINK) {
// Get MAC address from sockaddr_dl structure and store in nameToMac dictionary:
let dl = UnsafePointer<sockaddr_dl>(ptr.memory.ifa_addr)
let lladdr = UnsafeBufferPointer(start: UnsafePointer<Int8>(dl) + 8 + Int(dl.memory.sdl_nlen),
count: Int(dl.memory.sdl_alen))
if lladdr.count == 6 {
nameToMac[name] = lladdr.map { String(format:"%02hhx", [=10=])}.joinWithSeparator(":")
}
}
if addr.memory.sa_family == UInt8(AF_INET) || addr.memory.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(addr, socklen_t(addr.memory.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append( (name: name, addr: address, mac : "") )
}
}
}
}
}
}
freeifaddrs(ifaddr)
}
// Now add the mac address to the tuples:
for (i, addr) in addresses.enumerate() {
if let mac = nameToMac[addr.name] {
addresses[i] = (name: addr.name, addr: addr.addr, mac : mac)
}
}
return addresses
}
您必须添加
#include <ifaddrs.h>
#include <net/if_dl.h>
到桥接头文件进行编译。
用法示例:
for addr in getInterfaces() {
print(addr)
}
// ("en0", "fe80::1234:7fff:fe2e:8765%en0", "a9:55:6f:2e:57:78")
// ("en0", "192.168.2.108", "a9:55:6f:2e:57:78")
// ...
更新 Swift 3 (Xcode 8):
func getInterfaces() -> [(name : String, addr: String, mac : String)] {
var addresses = [(name : String, addr: String, mac : String)]()
var nameToMac = [ String: String ]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return [] }
guard let firstAddr = ifaddr else { return [] }
// For each interface ...
for ptr in sequence(first: firstAddr, next: { [=13=].pointee.ifa_next }) {
let flags = Int32(ptr.pointee.ifa_flags)
if let addr = ptr.pointee.ifa_addr {
let name = String(cString: ptr.pointee.ifa_name)
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
switch Int32(addr.pointee.sa_family) {
case AF_LINK:
// Get MAC address from sockaddr_dl structure and store in nameToMac dictionary:
addr.withMemoryRebound(to: sockaddr_dl.self, capacity: 1) { dl in
dl.withMemoryRebound(to: Int8.self, capacity: 8 + Int(dl.pointee.sdl_nlen + dl.pointee.sdl_alen)) {
let lladdr = UnsafeBufferPointer(start: [=13=] + 8 + Int(dl.pointee.sdl_nlen),
count: Int(dl.pointee.sdl_alen))
if lladdr.count == 6 {
nameToMac[name] = lladdr.map { String(format:"%02hhx", [=13=])}.joined(separator: ":")
}
}
}
case AF_INET, AF_INET6:
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(addr, socklen_t(addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
let address = String(cString: hostname)
addresses.append( (name: name, addr: address, mac : "") )
}
default:
break
}
}
}
}
freeifaddrs(ifaddr)
// Now add the mac address to the tuples:
for (i, addr) in addresses.enumerated() {
if let mac = nameToMac[addr.name] {
addresses[i] = (name: addr.name, addr: addr.addr, mac : mac)
}
}
return addresses
}
如果要在框架内使用它,则必须添加一个包含此配置的 .modelmap 文件
module ifaddrs [system] [extern_c] {
header
"/Applications/Xcode_7.3.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/ifaddrs.h"
export *
}
module net [system] [extern_c] {
module types {
header "/usr/include/sys/types.h"
export *
}
module if_dl {
header
"/usr/include/net/if_dl.h"
export *
}
}
然后在您的 .swift 文件中
import ifaddrs
import net.if_dl