From: Joachim Priesner Subject: ws2_32: WS_get_local_ips: Fix sorting IP addresses by metric if two addresses have the same metric Message-Id: <201410242227.52508.joachim.priesner@web.de> Date: Fri, 24 Oct 2014 22:27:50 +0200 The previous implementation required the metrics to be mutually inequal (because of the "this_metric > last_metric" check). If the metrics were not mutually inequal, it would write only one address per metric value to the list and fill up the rest of the list with the magic loopback IP address 127.12.34.56. I take it that this is not the expected behavior, please correct me if I'm wrong! --- dlls/ws2_32/socket.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 0bcce40..eb4539a 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -5171,13 +5171,14 @@ struct WS_hostent* WINAPI WS_gethostbyaddr(const char *addr, int len, int type) */ static struct WS_hostent* WS_get_local_ips( char *hostname ) { - int last_metric, numroutes = 0, i, j; + int numroutes = 0, i, j; DWORD n; PIP_ADAPTER_INFO adapters = NULL, k; struct WS_hostent *hostlist = NULL; PMIB_IPFORWARDTABLE routes = NULL; struct route *route_addrs = NULL; DWORD adap_size, route_size; + struct in_addr magic_loopback_addr_struct; /* Obtain the size of the adapter list and routing table, also allocate memory */ if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW) @@ -5251,29 +5252,34 @@ static struct WS_hostent* WS_get_local_ips( char *hostname ) hostlist->h_aliases[0] = NULL; /* NULL-terminate the alias list */ hostlist->h_addrtype = AF_INET; hostlist->h_length = sizeof(struct in_addr); /* = 4 */ - /* Reorder the entries when placing them in the host list, Windows expects - * the IP list in order from highest priority to lowest (the critical thing - * is that most applications expect the first IP to be the default route). + /* Sort the entries ascendingly by metric when placing them in the host list. + * Windows expects the IP list in order from highest priority to lowest + * (the critical thing is that most applications expect the first IP to be + * the default route). */ - last_metric = -1; + memcpy(&magic_loopback_addr_struct, magic_loopback_addr, 4); for (i = 0; i < numroutes; i++) { - struct in_addr addr; - int metric = 0xFFFF; + int lowest_metric = 0xFFFFE; + int lowest_metric_idx = -1; - memcpy(&addr, magic_loopback_addr, 4); for (j = 0; j < numroutes; j++) { - int this_metric = route_addrs[j].metric; - - if (this_metric > last_metric && this_metric < metric) + if (route_addrs[j].metric <= lowest_metric) { - addr = route_addrs[j].addr; - metric = this_metric; + lowest_metric_idx = j; + lowest_metric = route_addrs[j].metric; } } - last_metric = metric; - (*(struct in_addr *) hostlist->h_addr_list[i]) = addr; + + if (lowest_metric_idx != -1) + { + (*(struct in_addr *) hostlist->h_addr_list[i]) = route_addrs[lowest_metric_idx].addr; + /* Make this address not participate in any more comparisons. */ + route_addrs[lowest_metric_idx].metric = 0xFFFFF; + } else { + (*(struct in_addr *) hostlist->h_addr_list[i]) = magic_loopback_addr_struct; + } } /* Cleanup all allocated memory except the address list, -- 1.8.4.5