How to get the current connected Network Interface in MacOS

I want to ping to IPV6 via local-link address, which needs to get the current active Network Interface like Wi-Fi or Ethernet via adapter connection.

Like:

ping6 fe80::122b:41ff:feb3:6a20%en0                 

With en0 is the Wi-Fi Interface. I have tried :

private func getAllNetInterfaceName() -> [String] {
        let interfaces = SCNetworkInterfaceCopyAll() as? [SCNetworkInterface] ?? []
        return interfaces.compactMap { SCNetworkInterfaceGetBSDName($0) as? String }.filter { !$0.isEmpty }
}

It returns the array of the current Interfaces, but I still can not get which one is currently connected.

Did you have any clue?

Answered by lqk242 in 759262022

Thanks for your quick response. The key purpose is finding out the current connected Network Interface. Ex:

  • The Wi-Fi connection is en0 (default).
  • I used an adapter USB-C to RJ45 to connect a LAN connection → I could not find out which Network Interface is used for it programmatically. (sometime is en8, sometime is en15 and it depending on each different adapters I connected).

I used this function to get the current available Network Interface. Is there any newer supported function ? Can we use these lines of code for future?

public class EnumerateNetworkInterfaces {
    public struct NetworkInterfaceInfo {
        let name: String
        let ip: String
        let netmask: String
    }
    public static func enumerate() -> [NetworkInterfaceInfo] {
        var interfaces = [NetworkInterfaceInfo]()

        // 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) {

                let flags = Int32(ptr!.pointee.ifa_flags)
                var addr = ptr!.pointee.ifa_addr.pointee

                // 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) {

                        var mask = ptr!.pointee.ifa_netmask.pointee

                        // Convert interface address to a human readable string:
                        let zero  = CChar(0)
                        var hostname = [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        var netmask =  [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                                        nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                            let address = String(cString: hostname)
                            let name = ptr!.pointee.ifa_name!
                            let ifname = String(cString: name)


                            if (getnameinfo(&mask, socklen_t(mask.sa_len), &netmask, socklen_t(netmask.count),
                                            nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                                let netmaskIP = String(cString: netmask)

                                let info = NetworkInterfaceInfo(name: ifname,
                                                                ip: address,
                                                                netmask: netmaskIP)
                                interfaces.append(info)
                            }
                        }
                    }
                }
                ptr = ptr!.pointee.ifa_next
            }
            freeifaddrs(ifaddr)
        }
        return interfaces
    }
}

Best regards,

I want to ping to IPv6 via local-link address, which needs to get the current active Network Interface like Wi-Fi or Ethernet via adapter connection.

This goal doesn’t make sense as written because macOS [1]:

  • Can have multiple IPv6-capable interfaces active simultaneously

  • Each of those can have multiple link-local IPv6 addresses

Thus, it’s hard to answer your question with the details provider. Can you explain why you’re trying to do at a higher level?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

Thanks for your quick response. The key purpose is finding out the current connected Network Interface. Ex:

  • The Wi-Fi connection is en0 (default).
  • I used an adapter USB-C to RJ45 to connect a LAN connection → I could not find out which Network Interface is used for it programmatically. (sometime is en8, sometime is en15 and it depending on each different adapters I connected).

I used this function to get the current available Network Interface. Is there any newer supported function ? Can we use these lines of code for future?

public class EnumerateNetworkInterfaces {
    public struct NetworkInterfaceInfo {
        let name: String
        let ip: String
        let netmask: String
    }
    public static func enumerate() -> [NetworkInterfaceInfo] {
        var interfaces = [NetworkInterfaceInfo]()

        // 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) {

                let flags = Int32(ptr!.pointee.ifa_flags)
                var addr = ptr!.pointee.ifa_addr.pointee

                // 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) {

                        var mask = ptr!.pointee.ifa_netmask.pointee

                        // Convert interface address to a human readable string:
                        let zero  = CChar(0)
                        var hostname = [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        var netmask =  [CChar](repeating: zero, count: Int(NI_MAXHOST))
                        if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
                                        nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                            let address = String(cString: hostname)
                            let name = ptr!.pointee.ifa_name!
                            let ifname = String(cString: name)


                            if (getnameinfo(&mask, socklen_t(mask.sa_len), &netmask, socklen_t(netmask.count),
                                            nil, socklen_t(0), NI_NUMERICHOST) == 0) {
                                let netmaskIP = String(cString: netmask)

                                let info = NetworkInterfaceInfo(name: ifname,
                                                                ip: address,
                                                                netmask: netmaskIP)
                                interfaces.append(info)
                            }
                        }
                    }
                }
                ptr = ptr!.pointee.ifa_next
            }
            freeifaddrs(ifaddr)
        }
        return interfaces
    }
}

Best regards,

The key purpose is finding out the current connected Network Interface.

Two things:

  • Your request assumes that there is just one connected network interface. That’s not necessarily the case.

  • You don’t explain why you need this. In situations like this the correct answer varies based on your high-level goal.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Sorry about that, my intentions are:

  1. I want to get the current connected network interface (in case I don't use Wi-Fi (en0) any more, and use adapter instead)
  2. I want to use Simple Ping lib to ping to IPv6 local-link which need the exact network interface (the same with $sudo ping6 [IPv6 Local-Link]%[Network Interface])

Is there any way to ping to ipv6 to ensure that my connection is still alive without using this method above?

By the way, I still seek for the method to get MAC Address from IPv6 actually...

Best regards,

FYI, since you started this thread I’ve created a new post, Extra-ordinary Networking, that distills down a bunch of my experience in this space.

I still seek for the method to get MAC Address from IPv6 actually

So you’re end goal is to get the device’s MAC address? Are you trying to do that entirely on device? Or with the cooperation of some external hardware?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for your response. About this

So you’re end goal is to get the device’s MAC address?

Yes, that's it! We actually work on the TV devices using Wi-Fi.

Are you trying to do that entirely on device?

Yes, sure.

NDP protocol is a good deal, but I can not find its base code as ARP in Apple code. (In the window version of my app, I can use Win API : netioapi.h, and It works)

Or with the cooperation of some external hardware?

We have to do that in App, maybe there aren't any external devices to cooperate. The TV will support us to give back a Mac Address when I request on them in a few years later. But we want to get it programmatically.

I wrote:

So you’re end goal is to get the device’s MAC address?

You wrote:

Yes, that's it!

OK.

We actually work on the TV devices using Wi-Fi.

By “TV device” do you mean:

  • Your app is running on Apple TV?

  • Your app is running on iOS but it talks to a TV as an accessory?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Your app is running on Apple TV?

→ Our App will be supported to run in a specific brand's TV has TCP connection (which has IP address and Mac (Both Wi-Fi or LAN)).

Your app is running on iOS but it talks to a TV as an accessory?

→ We work for a brand that they want to get an App can send data to their TV model via TCP connection. And it only runs on macOS.

Thanks for the clarifications.

So, to be clear, iOS does not have any APIs that return the device’s MAC address. The MAC address is a persistent, sharable identifier, and Apple has been working hard to reduce access to those over the last N years [1].

One way to bypass this privacy limitation is with the cooperation of a Wi-Fi accessory. It naturally gets the MAC address of part of standard TCP/IP networking (ARP and so on). So, if you’re an iOS app in communication with that accessory, you can ask it to return the iOS device’s MAC address.

IMPORTANT This is can, not should. Before you do this, I recommend that you review your legal agreements with Apple and the App Store Review Guidelines.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] My favourite explanation of this is the WWDC session referenced by this post’s footnote.

How to get the current connected Network Interface in MacOS
 
 
Q