Packet Tunnel Provider - network type

I have a question regarding my VPN (Packet Tunnel Povider) app for MacOS:

Can I know if the user is connected by WIFI or by ethernet (wired/unwired)?

Is it possible that he is connected by both of them?



(A bonus question would be how can I tell if the connection type changes while using the VPN)

Accepted Reply

Yeah, good point. You can get this info out of BSD but at this point it’s probably easier to use System Configuration framework.

SCNetworkInterfaceCopyAll
will return an array of all network interfaces on the system. You can then use SCNetworkInterface APIs to get information about those interfaces, including the BSD name (
SCNetworkInterfaceGetBSDName
) and the interface type (
SCNetworkInterfaceGetInterfaceType
), which will be
kSCNetworkInterfaceTypeEthernet
for Ethernet and
kSCNetworkInterfaceTypeIEEE80211
for Wi-Fi.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

This response assumes you’re using TCP to connect to your VPN server. If not — if, say, you’re using UDP — things get more complex.

Can I know if the user is connected by WIFI or by ethernet (wired/unwired)?

With TCP you can get the source address from the TCP connection, map that to an interface, and then look at the characteristics of the interface.

Is it possible that he is connected by both of them?

Certainly a Mac can have both Ethernet and Wi-Fi interfaces up at the same time. When your provider connects to a server, the connection will use the appropriate interface based on that destination address (if the server is on the global Internet, it will use the default interface).

(A bonus question would be how can I tell if the connection type changes while using the VPN)

The best approach here depends on the API you’re using for the connection. If you’re using NWTCPConnection you typically watch for changes to the

hasBetterPath
property.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the response.

Unfortunately, I'm using UDP.

Is that still the way to go (get the source address, map that to an interface...)

Or is it a different approach?

Or maybe by more complex the best thing to do is skip this task for the Packet Tunnel Povider..?

UDP works in one of two modes:

  • If the socket is connected, the source address of the socket is bound at connect time and each datagram sent from that socket uses that source address.

  • If not, the source interface, and hence the source address, of each datagram is determined at send time.

What API are you using for UDP?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

The socket is connected (and I want to know to which interface)

What I have is the socket descriptor (UInt).

Call

getsockname
to get the source IP address. Then search for that address in
getifaddrs
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks, worked like a charm.

Last question on that topic - from my tests I can see that when connecting with wifi the interface name is en0,

and when connecting with ethernet (not wired) the interface is en4.

Is it something to count on?

(what I need is some mapping between interface name and wired/ not wired)


Edit: I saw this thread https://forums.developer.apple.com/thread/49581

So it's not possible to assume en0 is for wifi?

because that's what I'm trying to achive - report when the VPN is connected by wired and when it isn't.

Is it something to count on?

No.

On macOS you have lots of options for working out the interface type starting with the BSD interface name. Given that you’re already working with

getifaddrs
, you can find the link (
AF_LINK
) entry for that interface, follow its
ifa_data
to a
struct if_data
, and get the
ifi_type
from that. The relevant constants (
IFT_ETHER
and friends) are declared in
<net/if_types.h>
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks again eskimo !

But what I don't understand is if I can know if the connection type is wired or not, in both cases I'm getting IFT_ETHER

Yeah, good point. You can get this info out of BSD but at this point it’s probably easier to use System Configuration framework.

SCNetworkInterfaceCopyAll
will return an array of all network interfaces on the system. You can then use SCNetworkInterface APIs to get information about those interfaces, including the BSD name (
SCNetworkInterfaceGetBSDName
) and the interface type (
SCNetworkInterfaceGetInterfaceType
), which will be
kSCNetworkInterfaceTypeEthernet
for Ethernet and
kSCNetworkInterfaceTypeIEEE80211
for Wi-Fi.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Great success 🙂

Thanks!

Call

getsockname
to get the source IP address. Then search for that address in
getifaddrs
.


Hey, Quinn: those ManPages links that you posted result in ‘Page Not Found’ (as checked on June 13, 2018) — any idea what’s up?