Macchina-CLI / libmacchina

A library providing access to all sorts of system information.
https://crates.io/crates/libmacchina
MIT License
68 stars 20 forks source link

"LocalIP" readout is not very user-friendly on Windows #88

Closed FantasyTeddy closed 3 years ago

FantasyTeddy commented 3 years ago

I'm using macchina under Windows and the "LocalIP" readout does not work.

macchina --doctor output:

Readout "LocalIP" failed with message: Unable to get local IP address.

After some investigation, I found out that the if-addrs crate that is being used, uses some GUID as the name for an interface on Windows. So, if I use the configuration interface = "{578543CA-E953-487B-939B-B508CE96F84D}" I get an IP address in macchina.

To make matters worse (at least for me), each interface is listed twice with the same GUID: once with an IPv4 address and once with the corresponding IPv6 address. And unfortunately on my system the IPv6 address gets returned first and therefore is the one that gets displayed in macchina.

It would be awesome, if those two issues could somehow be addressed. Unfortunately I don't have a good idea, how it could be done.

grtcdr commented 3 years ago

{578543CA-E953-487B-939B-B508CE96F84D} is this Windows' concept of an interface name?

We can try and work with a different field if name is that horribly named on Windows. I'm not sure how that would work either, it'll take some experimenting for sure.

FantasyTeddy commented 3 years ago

I don't think that those GUIDs are meant to be a human-readable identification of the interfaces. As far as I can tell, those are some kind of device ID that is probably unique to the network adapter. But I'm just speculating.

Unfortunately, this probably means that you need to use a different crate to fetch the local IP address, since there don't seem to be any other properties exposed in if-addrs. (Or open an issue in if-addrs)

grtcdr commented 3 years ago

Before I answer your question, I need to ask: How does Windows identify network interfaces? What do interface names look like?

I'm not really willing to (globally) switch IP crates to support Windows' weird architecture. We'll have to make an exception for Windows as we do with other operating systems that do things differently, e.g. minor proc filesystem implementation differences between *nix systems, where instead of sharing the same function, we have multiple implementations/variants of them throughout the codebase.

I unfortunately don't have the time to work on this. Contributions are welcome, though. :)

FantasyTeddy commented 3 years ago

Unfortunately I am not an expert in this area. On my machine, the outgoing interface is called "Ethernet" and this seems to be the default for a single network adapter.

I understand that you don't want to change a dependency just for a single operating system, however if there were a crate available that has the same capabilities, but handles Windows better, would this be an argument to switch? After some digging, I found the local-ip-address crate that does exactly what we would want: either returns the local IP address without explicitly specifying an interface, or a list of all interfaces that could be filtered by name. If this would be a valid choice, I would gladly open a pull request with the necessary changes.

grtcdr commented 3 years ago

Unfortunately I am not an expert in this area. On my machine, the outgoing interface is called "Ethernet" and this seems to be the default for a single network adapter.

I doubt we can get the Local IP address of such a generic name, again, Microsoft doing Microsoft things, AKA abstractions where they have no right to exist.

I understand that you don't want to change a dependency just for a single operating system, however if there were a crate available that has the same capabilities, but handles Windows better, would this be an argument to switch?

Only for Windows, if-addrs is working wonders for *nix at the moment.

After some digging, I found the local-ip-address crate that does exactly what we would want: either returns the local IP address without explicitly specifying an interface, or a list of all interfaces that could be filtered by name. If this would be a valid choice, I would gladly open a pull request with the necessary changes.

We just switched from this crate, and it's limited in that:

FantasyTeddy commented 3 years ago

I doubt we can get the Local IP address of such a generic name, again, Microsoft doing Microsoft things, AKA abstractions where they have no right to exist.

What abstractions do you mean? They have to name it somehow and "Ethernet" seems quite descriptive to me.

We just switched from this crate, ...

I totally understand that you wanted something faster/more direct than making a detour through DNS. What if we use if-addrs for anything other than Windows and local-ip-address there?

grtcdr commented 3 years ago

What abstractions do you mean? They have to name it somehow and "Ethernet" seems quite descriptive to me.

Microsoft likes to make things generic, for some reason, and I really dislike that :(

I totally understand that you wanted something faster/more direct than making a detour through DNS. What if we use if-addrs for anything other than Windows and local-ip-address there?

I can't convince people that libmacchina talking to Google's DNS servers (that's what local-ip-address talks to by default) is necessary to get their Windows machine local IP address.

I've done some research and the GUID that you're using is the naming scheme that Windows uses to identify interface names.

But there's RFC2553, section 4.2 which details how you can get the UNIX like naming scheme from that GUID.

FantasyTeddy commented 3 years ago

I can't convince people that libmacchina talking to Google's DNS servers (that's what local-ip-address talks to by default) is necessary to get their Windows machine local IP address.

Are you sure this is also what local-ip-address does on Windows?

But there's RFC2553, section 4.2 which details how you can get the UNIX like naming scheme from that GUID.

What would be a good strategy to integrate the mentioned if_indextoname function into macchina? Should it be done only for Windows? Should it be done in if-addrs?

grtcdr commented 3 years ago

I can't convince people that libmacchina talking to Google's DNS servers (that's what local-ip-address talks to by default) is necessary to get their Windows machine local IP address.

Are you sure this is also what local-ip-address does on Windows?

Actually, I'm completely wrong here, I thought you were talking about local_ipaddress the whole time, which we recently just switched from.

What would be a good strategy to integrate the mentioned if_indextoname function into macchina? Should it be done only for Windows? Should it be done in if-addrs?

Yeah, it should be done for Windows only and outside if-addrs.

The logic should be: libmacchina receives an interface name as an argument to local_ip(), it then passes it to if_nametoindex(const char *ifname), compares the int returned by that function with the GUIDs that it's going to (hopefully) find when looping through the interfaces with if-addrs.

If it loops through and finds no matches, we can safely assume that the interface just doesn't exist, else we return the first match we find.

FantasyTeddy commented 3 years ago

Actually, I'm completely wrong here, I thought you were talking about local_ipaddress the whole time, which we recently just switched from.

Would you therefore consider switching to local-ip-address? Maybe we could run some benchmarks to compare the speed of if-addrs and local-ip-address.

I think implementing the workaround for Windows and if-addrs should only be done if there is no way around it.

grtcdr commented 3 years ago

I don't particularly mind switching, but we don't need to. the Windows API can help us do that without switching IP crates.