When I ask the GetIpAddrTable function to sort the results, how are they sorted?

Raymond Chen

Raymond

A customer had a question about the way the GetIpAddrTable function sorts the results. The documentation says that if you pass TRUE as the bOrder parameter, then the mapping table will be sorted upon return.

What exactly is this sorting order?

The customer observed that in practice, they got the IP addresses in this order: Public IP addresses, then internal addresses, and then local addresses. They were interested in obtaining the public IP address, so they just asked for the results to be sorted and the grabbed the first one.

That worked great until one day, they grabbed the first sorted address and got the local address 127.0.0.1. Did this mean that the system didn’t have any public IP addresses? The customer is trying to figure out why there was no public address, or at least no public address that the GetIpAddrTable function could find.

The problem is that their assumption wasn’t supported by the documentation. The documentation says that the bOrder parameter controls “whether the returned mapping table should be sorted in ascending order by IPv4 address.”

The sorting is done by IPv4 address, not by scope or availability or subnet or routing or broadcast. Specifically, the sorting is done in lexicographical order by the IPv4 address in network byte order.

The following table lists the IPv4 addresses in sorted order (not to scale):

Dotted notationNetwork byte orderdwAddressNotes
0.0.0.000 00 00 000x00000000Local
0.0.0.100 00 00 010x01000000
0.255.255.25400 FF FF FE0xFEFFFF00
0.255.255.25500 FF FF FF0xFFFFFF00
1.0.0.001 00 00 000x00000001Public
1.0.0.101 00 00 010x01000001
9.255.255.25509 FF FF FF0xFFFFFF09
10.0.0.00A 00 00 000x0000000APrivate
10.0.0.10A 00 00 010x0100000A
10.255.255.2550A FF FF FF0xFFFFFF0A
11.0.0.00B 00 00 000x0000000BPublic
(mostly)
11.0.0.10B 00 00 010x0100000B
126.255.255.2557E FF FF FF0xFFFFFF7E
127.0.0.07F 00 00 000x0000007FLoopback
127.0.0.17F 00 00 010x0100007F
127.255.255.2557F FF FF FF0xFFFFFF7F
128.0.0.080 00 00 000x00000080Public
(mostly)
128.0.0.180 00 00 010x01000080
255.255.255.255FF FF FF FF0xFFFFFFFF

Note that the areas marked “Public (mostly)” contain islands of private or other special addresses within them. The purpose of this list was not to break down the entire IPv4 address range. It was to highlight that lexicographical ordering by IPv4 address in network byte order has no relation to the nature of the address.

I suspect what happened is that the company’s public IP address assignment moved from an address less than 127.0.0.0 to one greater than 128.0.0.0, which means that 127.0.0.1 is now the numerically lowest IP address.

The sorting performed by the GetIpAddrTable is purely numerical by IPv4 address. If you want to fish out your system’s public IP address, you’ll have to do your own filtering.

Bonus chatter: I listed IPv4 addresses like 0.0.0.1, even though 0.0.0.1 is strictly speaking not a valid IPv4 address. The IP_MULTICAST_IF socket option uses values of this form to mean “Not an address, but an interface index.”

 

2 comments

Comments are closed. Login to edit/delete your existing comments

  • Avatar
    Ian Boyd

    Bonus: since we are now after 2001, you should be using the GetAdaptersAddresses function instead; which supports both kinds of Internet Protocol addresses (i.e. both version 6 and version 4 IP addresses)

  • Avatar
    Dave Gzorple

    This is a great example of programmers implementing something that’s convenient for them and not for the user (before people get defensive about this, I’m commenting on programmers in general, not Microsoft specifically). Sorting by an essentially useless metric is easy because they just call qsort() on the array, but if the caller wanted that they could call qsort() themselves. What the caller probably wants is addresses sorted in the order of usefulness, e.g. the currently active in-use address at the top, loopback addresses and other noise at the bottom.

    Yes, I know you can come up with all sorts of corner cases, but I’d guess most users (callers of the function) want the address that’s most likely to work/be useful/in use towards the top, which requires a bit of work rather than just passing the array to qsort().