Comment by kelnos

Comment by kelnos 3 days ago

89 replies

It's a little weird to me that getaddrinfo() is considered a "low-level legacy API". Maybe things are drastically different on macOS, but getaddrinfo() is the way to resolve names on Linux and I suspect the *BSDs.

Sure, I expect most macOS apps will use something in Foundation or some other NetworkKit-type framework to do DNS queries, but it's odd to me that the code there wouldn't then call down to getaddrinfo() or the like to do the dirty work. I guess GAI is blocking, so presumably there's some other low-level non-blocking call?

krackers 3 days ago

>so presumably there's some other low-level non-blocking call

Correct, CFNetwork is open source so you can check implementation but last I remember it used some variant like `getaddrinfo_async`. But Apple really doesn't want you (the end-user) to use getaddrinfo (or the async variant CF exposes) to resolve an IP and then directly connect() via that ip, everything is geared towards connect-by-hostname since then Apple's can internally handle the implementation of happy-eyeballs.

Edit: You can read https://www.ietf.org/proceedings/72/slides/plenaryw-6.pdf for their thoughts on why they don't like the getaddrinfo() model [there are speaker notes at the bottom of each slide]

  • conradev 3 days ago

    If you do need the lower-level control, Apple does still recommend `getaddrinfo`. It handles NAT64 translation for IPv6-only carrier networks:

    https://developer.apple.com/library/archive/documentation/Ne...

    • simscitizen 2 days ago

      That’s not the current documentation, as evidenced by the “archive” in the URL.

      If you want to stay at a lower level the recommendation these days is to use Network.framework. If you want something higher level then use CFNetwork (probably through the classes exported by Foundation like NSURLSession).

      • conradev 2 days ago

        I actually found it linked from here, which seems current: https://developer.apple.com/support/ipv6/

        It is not best practice to use `getaddrinfo` for DNS resolution, for sure. But it is best practice to use it before connecting to an IP address directly because that address may need to be translated.

    • krackers 3 days ago

      I'm actually surprised they suggest getaddrinfo() directly over the async CF wrapper.

  • Terretta 2 days ago

    TL;DR:

    Applications should not use getaddrinfo(). Because for the connect by name, the OS or app SDK can parallelize the entire multi-step lookup and connection process, not just step by step:

    “Now, I’m not saying that all implementations of these APIs [Java, Apple Foundation, etc., doing connect by name] necessarily do the right thing today, but if applications are using these APIs, then the implementations can be improved over time.”

    “The difference with getaddrinfo() and similar APIs is that they fundamentally can’t be improved over time. The API definition is that they return you a full list of addresses, so they have to wait until they have that full list to give you. There’s no way getaddrinfo can return you a partial list and then later give you some more.”

    The deck's position on implementation of happy-eyeballs (which could sound dismissive here but is treated as "you had one job" important by the deck), is finding a way to avoid waiting 5 seconds for either side of IPv4 vs. IPv5 stack to timeout before finishing connection setup and serving the user a web page.

  • matheusmoreira 2 days ago

    Thanks for that link, it's a very convincing presentation that very clearly explains the shortcomings of getaddrinfo.

    • SOLAR_FIELDS 2 days ago

      Yeah, I went in thinking that it was going to be some case of Apple wanting to bend the Unix philosophy to their will for their own desires and steer implementations in their direction, but no - they are simply pointing out a clear flaw in the design of the function in question for a usecase that does not apply only to Apple. Basically all OS vendors need to be doing something like this usecase to support IPv6 adoption.

      • marxisttemp 2 days ago

        I often find this is the case with Apple on a technical level.

        For instance, their recent Spatial (stereographic) Video features uses a format that has basically zero current support outside of Apple—which is in fact just standard MV-HEVC [0] (with some extra optional metadata [1]), which is just the H.265 evolution of the standard H.264 MVC that 3D Blu-rays have used for a long time. (AFAIK no 4K 3D Blu-rays have been released, presumably due to space constraints, explaining the lack of usage of MV-HEVC outside Apple).

        In piracy world, most re-encoded 3D movies just use objectively inferior composited 2D formats like half-side-by-side or over/under. And without diving in you’d just assume Apple was using some bespoke format to be evil, when in fact they are popularizing what should be the canonical, standardized format for 3D video.

        [0] http://hevc.info/mvhevc [1] https://developer.apple.com/av-foundation/HEVC-Stereo-Video-...

jmull 3 days ago

> It's a little weird to me that getaddrinfo() is considered a "low-level legacy API"

I don't think it is considered legacy. The blog post gets that wrong.

(Whether it's "low-level" or not just depends on your perspective.)

matheusmoreira 2 days ago

> getaddrinfo() is the way to resolve names on Linux

Not at all. That's just a glibc function, it's got nothing to do with Linux. People just assume that glibc is how things are done in Linux user space but it doesn't have to be that way. For example, systemd came up with its own resolved mechanism which turned out to be much better than the glibc stuff. I will probably end up inventing my own at some point as well since I'm working on freestanding software targeting Linux.

  • jonhohle 2 days ago

    getaddrinfo is defined by POSIX and UNIX. Where the implementation is doesn’t matter. It’s portable, which is why it’s used. The slide deck referenced above talks about better implementations for various platforms, but they are all platform specific.

    So OP might not be completely accurate, but getaddrinfo is _the_ way to resolve names if you are writing portable POSIX and/or UNIX code.

    • matheusmoreira 2 days ago

      Linux and the popular Linux distributions are not POSIX compliant to begin with. Only GNU tries to be, and even GNU adds on a ludicrous amount of extensions because the truth is POSIX isn't good enough.

      • Tepix 2 days ago

        Why are you nitpicking? Linux demonstrates a high degree of practical compatibility to run software written against POSIX standards.

        • matheusmoreira a day ago

          Not nitpicking at all. I just don't like how people see Linux as a "POSIX implementation". It's much more than that.

          Practical compatibility is not compliance, the manuals document many subtle differences and incompatibilities. The practicality of it mostly comes from glibc which everyone uses and which does strive to be compliant. Even then it's a hit and miss, the so called "Linuxisms" crop up in the most unexpected of places. The executable path that people write in the shebang lines of their shell scripts, for example. It's gotten to the point some BSDs have started emulating Linux system calls instead of porting software. Even Windows did this once upon a time.

          My point is glibc is not even guaranteed to exist on the system. POSIX is not at all mandatory on Linux. The POSIX interfaces are just one of the ways to interface with the kernel. It's also possible to bypass all the POSIX stuff and interface with it directly. Linux is the only operating system to offer this ability via the stable kernel-userspace binary interface. It's even defined at the instruction set level which makes it programming language agnostic. On Linux you actually can trash all that POSIX stuff and reinvent it all in Rust if you want.

      • throw0101a 2 days ago

        > Linux and the popular Linux distributions are not POSIX compliant to begin with.

        While not (entirely) wrong, not entirely correct either.

        Good luck trying to compile and run any kind of software without providing getaddrinfo(), socket(), connect(), etc to userland:

        * https://pubs.opengroup.org/onlinepubs/9699969599/functions/g...

        • matheusmoreira a day ago

          > Good luck trying to compile and run any kind of software without providing getaddrinfo(), socket(), connect(), etc

          I'm working on a freestanding lisp language with built in Linux system call support at least in part because I want to to prove that this sort of thing is possible. No legacy interfaces will be provided and yet I have no doubt in my mind that one day it will be able to everything you mentioned and much more.

      • jonhohle 2 days ago

        Your comment above was that it is a glibc function, which is true, but it’s there for reason. It’s also a libc, musl, uClibc, and Windows Sockets 2 function: because it’s defined in POSIX 1.1 and extended in RFC 3493.

        I have no opinion on whether it’s good enough (it seems like not if every platform has a connect-by-name implementation), just that calling it a glibc function overly simplifies it’s origin.

        It’s also false to say only GNU tries to be POSIX compliant. There are 8 commercial UNIXes that meet some POSIX standard, another 8 that are discontinued (at least one of which was a Linux distro), and dozens that are mostly compatible. POSIX doesn’t care if that compatibility comes from the kernel or user space libraries.

        POSIX isn’t good enough at what? Maybe you don’t understand what it’s goal is/was. POSIX exists for portability. It’s a minimal set of functions developers can target to get things done on any UNIX. Any OS will always have something beyond POSIX to differentiate it.

        • matheusmoreira a day ago

          The point I tried to make is the getaddrinfo function is not sacred. It's not the way to do anything at all on Linux. It's just the function that glibc has, and most people use it. Whether it came from POSIX or something else seems like a minor detail to me. POSIX and glibc are not sacred either.

          > Any OS will always have something beyond POSIX to differentiate it.

          Linux is no exception. We should all be enjoying those exclusive features to their fullest extent. Not restricting ourselves to the lowest common denominator between them. Portability is a trap.

  • yrro 2 days ago

    You're probably aware of c-ares, if not then check it out unless you really want to write your own.

    (As an administrator I'm getting a bit tired of working around the differing bugs and behaviour of different resolver implementations).

    glibc also has an async getaddrinfo_a function for asynchronous name resolution, with completion notification.

    • matheusmoreira a day ago

      I will look into it even if I end up writing my own. Reading source code is always helpful. Thank you.

pushupentry1219 2 days ago

> Maybe things are drastically different on macOS, but getaddrinfo() is the way to resolve names on Linux and I suspect the *BSDs.

I'm not sure if this is the case in this case, but it might be worth noting that some system functions with the same name have drastically different internal/implementation differences between Linux/*BSD/MacOS. With there being differences between the *BSDs too.

So on some systems one function call is "the way", because its been maintained over the years, but then on another it might actually be old and not useful.

adastra22 2 days ago

Everything in the UNIX compatibility layer is low-level in macOS. Not necessarily "legacy" though.

But this is no different than saying that, for example, calling out platform-specific native OS APIs from Java is "low-level." Which it is, from the perspective of compile-once, run-anywhere Java applets. macOS is a NeXT-compatible non-UNIX API, and you are supposed to use the macOS frameworks for everything. Calling down to BSD or even mach is definitely not what Apple wants you to do.

  • hmage 2 days ago

    > macOS is a ... non-UNIX

    Seems to be badly phrased and meant something else, since macOS is certified to be UNIX - https://www.opengroup.org/openbrand/register/ - contrary to Linux which is not UNIX-certified.

    HN posted about this at least once - https://news.ycombinator.com/item?id=29984016

    • adastra22 a day ago

      UNIX is/whas a commercial product from AT&T. macOS is UNIX-certified. Not the same thing.

  • raverbashing 2 days ago

    Curious about this

    Isn't the Mach kernel based on BSD?

    How much of getaddrinfo is in the kernel, how much of it is pure "libc"?

    • adastra22 2 days ago

      No, mach is a microkernel, like L5. It was developed for the purpose of replacing the BSD kernel, by having a small amount of functionality in the kernel itself, and the rest of the BSD-compatibility layer implemented in user space. macOS' frameworks are then a layer on top of that.

      • messe 2 days ago

        IIRC most of the BSD compat was moved to kernel space for performance reasons (either just on macOS, or the version of Mach they built on top of)

        • egberts1 2 days ago

          The UNIX libcompat (a compatibility library for older UNIX functions) was integrated into Mac OS (specifically, macOS) rather than directly into Mach OS.

          Here’s the breakdown:

          • Mach OS refers to the Mach microkernel, which primarily focuses on low-level system functions such as task scheduling and memory management. It is not a full-fledged operating system, and thus, libraries like libcompat, which are higher-level UNIX compatibility libraries, would not be integrated directly into the Mach kernel itself. • Mac OS (particularly macOS, formerly OS X) is a complete operating system that includes the Mach microkernel, the BSD layer, and various other components. macOS has a strong Unix heritage, and libcompat is part of the broader Unix-like environment included in macOS to support legacy Unix APIs and applications.

          Thus, libcompat was integrated into macOS (or its predecessor, NeXTSTEP) as part of its Unix compatibility layer, rather than into the Mach kernel directly

pjmlp 2 days ago

For quite some versions that modern networking APIs on macOS using Objective-C frameworks, starting in 2018.

See WWDC 2018's "Introducing Network.framework, A modern alternative to sockets".

NeXTSTEP might have been a UNIX, and macOS derives from it, but the whole UNIX story has always been to bring UNIX software into the platform, not to make it easier to move elsewhere.

egberts1 2 days ago

Of course, Apple does not want their app to call `getaddrinfo()` directly, because it would interfere with their internal XDR/NDS/IPS mechanism.

I can’t blame them but I personally would still have my apps use them, even knowingly that it would be made off-limit to iOS/iPadOS apps … soon.

unethical_ban 3 days ago

I'll pile on, as someone who has never developed for Apple systems: What APIs are supposed to be used for DNS resolution?

  * Host file
  * Configured DNS server
  * App-specific DNS server if it exists
What "API" is there? Why doesn't an app doing system-wide DNS modifictions just modify the settings for default resolver?
  • Terretta 2 days ago

    The Apple deck linked elsewhere in this thread suggests the developer's goal generally isn't "DNS resolution", the dev's goal is usually establishing a connection to a host/server/endpoint to start doing something.

    So, usually devs should use the Java or Apple or whatever higher level OS API gets you connected the fastest, and that API is free to implement the connection however most quickly gets to the point of able to return data to the user (app or end user).

    The API that returns a list of addresses is stuck doing that, instead of being able to parallize the entire "get connected" data flow.

  • threeseed 3 days ago

    > This library wraps around the dnssd framework and the c-ares C library with Swift-friendly APIs and data structures.

    https://github.com/apple/swift-async-dns-resolver

    • josephcsible 3 days ago

      It feels like Embrace, Extend, Extinguish to claim that a portable API is "legacy" and that its replacement is Apple-only.

      • matheusmoreira 2 days ago

        It's not necessarily EEE. Maybe it's just that the old wheel sucks. They want a better wheel and so they reinvented it, hopefully better this time.

        The corporations making proprietary software are not the only ones who have that attitude. I've resolved to make all my free software Linux-exclusive so that I can use Linux to the fullest. The Linux kernel is packed full of exclusive non-portable features that very few people take advantage of because they're obsessed with portability, POSIX compliance or whatever. I think that's a waste.

        Portable software is usually sucky lowest common denominator software. We should not limit ourselves to whatever glibc offers.

      • tpmoney 3 days ago

        As near as I can tell, Apple doesn't call it a legacy API. The article does, but the article wasn't written by nor does it appear to be quoting Apple.

      • [removed] 3 days ago
        [deleted]
      • threeseed 2 days ago

        You actually think that a Swift developer, developing against Cocoa APIs, targeting Mac and iOS devices cares about a portable API.

        Because not sure if you know this but the entire software industry is built on high level libraries on top of largely portable code. For example this Swift library wraps c-ares a portable API.

      • [removed] 3 days ago
        [deleted]
      • ryandrake 2 days ago

        It's the same thing they did with Metal. Portable OpenGL is now "legacy." Straight from the 90s Microsoft playbook.

      • kccqzy 2 days ago

        Well but the portable API is too low-level and error prone. What is the last time you used getaddrinfo? How often do you actually need to use it?

        One can make a good technical argument based on the merit of the portable API without immediately resorting to the EEE argument.

  • roywashere 3 days ago

    Yes, this! I even wonder how else you would do this. By the way I worked with many IoT devices that do not use your dhcp dns but just hardcode quad 8 or similar

    • cj 3 days ago

      We recently had a developer join our team and he got stuck setting up his dev environment.

      We use a .dev domain as a localhost alias, and turns out his ISP’s DNS wouldn’t resolve 127.0.0.1 (or whatever it is) for the .dev domain. Changing his resolver at the network level to 1.1.1.1 fixed it.

      I imagine there are lots of difficult support tickets for app devs, and at a certain point they just hardcode the DNS to remove one variable from the equation when debugging bug reports.

      • troyvit 2 days ago

        Wayyyy back in 1995 or '96 I was working for a non-profit called "Next Generation Magazine" and our goal was to have young people write content for web sites to get their names out there. Back then it was all local ISPs, so we went to our ISP and asked for ngm.org and were stoked when we got it! We built out the site (Thanks to Building Killer Websites of course) and it looked awesome!

        Only problem was that nobody in my family out of state could see it. It took awhile to realize realize that we never bought that domain. Our local ISP just added it to their DNS records, and since we all hooked into them we thought we were live across the 'net.

        • jonhohle 2 days ago

          That’s incredible!

          I remember one of the first times I used the Internet and opened my local radio station’s website from several states away. It was incredible to me that it worked and I also wondered why anyone across the country would care. The early internet was amazing.

      • X-Istence 3 days ago

        Not resolving 127.0.0.1 or RFC1918 addresses or even ULA for IPv6 is done to avoid DNS rebinding attacks. For most end users that is probably the correct move.

    • admax88qqq 2 days ago

      Most isp resolvers are shit and broken

      • egberts1 2 days ago

        That’s why it is imperative (at least, for a homelab hobbyist) to host your own DNS servers in your own VSP.

        • admax88qqq 2 days ago

          Totally, but most IoT customers are not homelab hobbyists, so I think its defensible for IoT vendors to just hard code known good DNS in their devices instead of relying on broken ISP resolvers.

          Related story, there was a period of time where my ISP's resolver that would replace hostnames with no DNS record with their own ad filled garbage page.

          So you mistype google.com to foofle.com or something and instead of getting "host not found" you get... ads.

          Disgusting behaviour IMO.

ajross 2 days ago

Yeah, this report seems a little spun. The essence is basically that the encrypted DNS needs to go through the proxy, and there's resolver code elsewhere in the OS that doesn't use the proxy. It's a bug, sure. It could plausibly have interesting exploits, though none are shown. But it's not a very interesting bug.

ransom1538 2 days ago

Wait until you try to get the mac address on an iphone.

mannyv 3 days ago

Yes, things are drastically different on MacOS. There's like a whole nother level of APIs ip there

/s