'connect' to device from iPad/iPhone/mac via USB-C ethernet adapter in link-local mode fails

We have an issue with creating an ordinary TCP socket connection to a device that is connected on a link-local net (simple peer to peer Ethernet). Our code is in C++ and we use the normal POSIX socket API.

The scenario is like this:

  1. We have a device with ordinary Ethernet connected to a USB-Ethernet adaptor.
  2. We plug in the USB-Ethernet adaptor in a Mac or iPad.
  3. The device establishes link-local IP address and announces a service via mDNS/DNS-SD
  4. The Mac/iPad Bonjour system picks up the device service and we get the information in our app.
  5. Our app want to connect to the service using a normal TCP socket connection to the device's link-local address.

So far this is normal and working as expected. However from here something unexpected happens:

  1. We create a "socket()" and do a "connect()". 
  2. WireShark shows that the TCP connection is established on the correct interface, with the correct destination IP/port, but with a source IP/port from a different interface. Fx. the TCP SYN from the Mac has destination ip 169.254.5.253 (correct) but source IP 192.168.1.101 (wrong - that IP does not exist on that interface). Consequently the TCP connection never get established.

Workaround: We have found out that using "bind()" to bind the socket to a specific source link-local IP on the relevant interface works. Then the TCP SYN comes out with correct source IP. However binding an outgoing TCP that is a very unusual thing to and we are surprised that it doesn't just work without it.

Other information: Parts of this issue seems to be timing related. Without the "bind()" it sometimes works if we retry the connect after timeout. Occasionally it works the first time. Having a Ethernet switch in between also sometimes helps.

Have we missed something or is this a problem in macOS/iOS?

Thanks! :)

Do ifconfig on your Mac and see if any of the interfaces has configured link local IPv4 address from 169.254.x.x subnet.

Jsut checked my Ventura and I do not have any.

If you do not have one on your Mac, link local communication over IPv4 will not work. The fact that you even see ougoing SYN is strange.

You can try using IPv6 however, because with IPv6 all interfaces are guaranteed to have link local address (prefix fe80::) always assigned and usable.

For IPv4 I do not believe the behavior is standartized, and link local addresses are only assigned when there is no static IP, and DHCP fails.

So if your Mac is on WiFi or ethernet, it might not have link local IPv4 configured by default.

my .2 cents, Martin

Hi @enodev and thanks for your reply. Here are some follow up responses:

  1. We did check with ifconfig and the interface does get a link-local address as expected. That is also why we can "bind()" to it. "getifaddrs()" returns information that is consistent with ifconfig.
  2. The outgoing SYN is part of establishing a TCP connection so that is normal even for link-local interfaces. The odd part is the source IP does not match the interface IP.
  3. Unfortunately IPv6 is not available in this scenario.
  4. Link-local is in fact standardized in RFC 3927 although it leaves room for some implementation defined behavior (timeouts, etc). Link-local is included in MacOS as a part of Bonjour.

I’m going to use the term accessory to refer to your device because in Apple Land™ device refers to the iOS device.

Link-local IPv4 is a pain. Before we go further, can you check whether this works with Network framework? That is, find the accessory with NWBrowser and connect with NWConnection (nw_browser_t and nw_connection_t in C). Does that work?

Share and Enjoy

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

Thanks @eskimo - I just knew there would be a reply from you ♥️

Oops - we will try to use the term 'accessory' from now on here in Apple Land™ 😅

And ok then will try look into start using the Network framework instead. Will get back to you if we manage to do that soon, thanks!

'connect' to device from iPad/iPhone/mac via USB-C ethernet adapter in link-local mode fails
 
 
Q