Best way to get your own IPs

What's the best way in rust for a host get a list of its own IPs? I've seen some crates like this but they:

  • Don't seem to be very robust because they're parsing output of shell commands like ifconfig
  • They probably won't work for Windows which I also need to support.

Is pnet crate an option? I'm concerned because it seems to require existence of WinPcap on Windows to work. Or is this just for building it in Windows?

3 Likes

On Unix, you can use getifaddrs. Here's some code I wrote up to grab the basics out: https://gist.github.com/sfackler/d614e6c130f3462f443e6c0c6255383a.

On Windows, I think you can use GetAdaptersAddresses but I haven't actually messed with that personally.

1 Like

Thanks @sfackler. I was aware of those APIs, but was wondering if there's already a cross-platform crate for this. Maybe libpnet will do the job for me for now, but it's too big and kinda awkward to build on Windows and maybe even to use there.

I guess I can write a crate using the standard APIs (those you mentioned) myself.

For windows there is ipconfig: https://crates.io/crates/ipconfig

Thanks @SergejJurecko for suggesting that. ipconfig does seem to be in decent shape, but I don't like the fact that it returns its results in a vector. Ideally it should be returning an iterator.

I’m surprised this isn’t in std. @sfackler, are there fundamental issues with this across supported Rust platforms? Or just nobody has looked into it?

Yesterday I realized that UdpSocket in std doesn’t seem to allow setting SO_REUSEPORT, which is needed when wanting to bind to a multicast group when there’s an existing listener on that address.

All that to say that networking support in std is a bit barebones.

3 Likes

libc provides an extraordinarily large API surfce. I don't see why it would be incredibly surprising that people haven't put the effort into implementing and stabilizing interfaces to arbitrary bits of it.

I’m not saying all of libc but wanting to get your own interfaces is pretty mundane, no?

1 Like

The fact that no one has actually implemented a wrapper around this interface until now may indicate how commonly this API is used, no?

How do you know that? Because someone didn’t put it up on crates.io? I don’t think people will put up single functions here and there - doesn’t make sense, they’ll just impl it internally and move on.

There’s little point in debating the popularity of this API here though. I was merely surprised that this bit wasn’t in there (and the UdpSocket one I mentioned) given it’s not very exotic and seems to have a native API across the supported platforms (at least Tier 1). But I’m not complaining, just expressing surprise.

2 Likes

Go's standard lib has quite a rich set of APIs in this area: net package - net - Go Packages which are obviously cross platform.

In fact I was thinking of modelling the code in my own crate, which I'm planning to write, after Go's API surface.

Edit: Unfortunately Go makes the choice earlier on in the retrieval process to push everything into a vector and then return the vector which I was hoping to avoid in Rust. The core problem is that the structure of data returned by Linux and Windows is quite different. Ensuring a common return structure will necessitate one of the OSes having to suffer some extra processing or allocation. Windows returns the information already arranged interface-wise while Linux (or libc) returns it in terms of individual addresses. From an ergonomic perspective I like "Interface" as a unit of packaging. So I feel it's Linux that'll have to suffer some perf penalty in order to have it's data transformed into Interface objects. What we can do is expose an additional "Ext" trait which will also expose the zero-cost access to getifaddrs in case someone wants to directly use that.

Further edit: Well, upon further reading of Go's code it doesn't seem to be using getifaddr for linux at all. It appears to use some netlink APIs which do return information arranged interface-wise quite like Windows. So there's probably no need to reconcile between different structures. But Go is still putting everything in vectors. I think Rust can easily return iterators in this case and thus avoid perf costs mentioned above.

3 Likes

Exactly!

This is prerequisite for better rust adoption. Referred go lib was one of the reasons of it's success.

If you are looking for an idiomatic library-provided way to do this, nix recently got support for getifaddrs: https://github.com/nix-rust/nix/pull/667

Moreover, Go had troubles due to its kitchen-sink stdlib. Most of the low-level functions are now being moved out of it, see the top NOTE in the syscall package: syscall package - syscall - Go Packages

1 Like

Excellent news. Thanks @lucab. :slight_smile:

There's also a crate specifically for this: https://crates.io/crates/get_if_addrs

1 Like

GPL license makes it off limits for most.

Sometimes owners do not know about GPL issues and just assign any first they heard about. Fee times I asked owners to change a license or make dual. My requests have been addressed. Try in this instance.

I'd be more concerned about that Contributor Agreement.

I'm assuming it's known but do you really want the ip addresses currently assigned directly to the nic (e.g. ifconfig) or do you want the IP address that other machines can access it from?

These are not always the same thing!