From 413eeaead5c584335c979766100f952b1e2f8cd0 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 2 Aug 2021 09:19:07 +0100 Subject: [PATCH] iphlpapi: Implement AllocateAndGetIpForwardTable() on top of GetIpForwardTable(). Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/iphlpapi/iphlpapi_main.c | 37 +++++ dlls/iphlpapi/ipstats.c | 265 ---------------------------------- 2 files changed, 37 insertions(+), 265 deletions(-) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 7637553780a..4b13b42fc6a 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -2278,6 +2278,43 @@ err: return err; } +/****************************************************************** + * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@) + * + * Get the route table. + * Like GetIpForwardTable(), but allocate the returned table from heap. + * + * PARAMS + * table [Out] pointer into which the MIB_IPFORWARDTABLE is + * allocated and returned. + * sort [In] whether to sort the table + * heap [In] heap from which the table is allocated + * flags [In] flags to HeapAlloc + * + * RETURNS + * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes + * on failure, NO_ERROR on success. + */ +DWORD WINAPI AllocateAndGetIpForwardTableFromStack( MIB_IPFORWARDTABLE **table, BOOL sort, HANDLE heap, DWORD flags ) +{ + DWORD err, size = FIELD_OFFSET(MIB_IPFORWARDTABLE, table[2]), attempt; + + TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags ); + + for (attempt = 0; attempt < 5; attempt++) + { + *table = HeapAlloc( heap, flags, size ); + if (!*table) return ERROR_NOT_ENOUGH_MEMORY; + + err = GetIpForwardTable( *table, &size, sort ); + if (!err) break; + HeapFree( heap, flags, *table ); + if (err != ERROR_INSUFFICIENT_BUFFER) break; + } + + return err; +} + static void forward_row2_fill( MIB_IPFORWARD_ROW2 *row, USHORT fam, void *key, struct nsi_ip_forward_rw *rw, void *dyn, struct nsi_ip_forward_static *stat ) { diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c index 43c481c749f..7bb4ff0603e 100644 --- a/dlls/iphlpapi/ipstats.c +++ b/dlls/iphlpapi/ipstats.c @@ -1220,271 +1220,6 @@ static void *append_table_row( HANDLE heap, DWORD flags, void *table, DWORD *tab return table; } -static int compare_ipforward_rows(const void *a, const void *b) -{ - const MIB_IPFORWARDROW *rowA = a; - const MIB_IPFORWARDROW *rowB = b; - int ret; - - if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret; - if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret; - if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret; - return rowA->dwForwardNextHop - rowB->dwForwardNextHop; -} - -/****************************************************************** - * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@) - * - * Get the route table. - * Like GetIpForwardTable(), but allocate the returned table from heap. - * - * PARAMS - * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is - * allocated and returned. - * bOrder [In] whether to sort the table - * heap [In] heap from which the table is allocated - * flags [In] flags to HeapAlloc - * - * RETURNS - * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes - * on failure, NO_ERROR on success. - */ -DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder, - HANDLE heap, DWORD flags) -{ - MIB_IPFORWARDTABLE *table; - MIB_IPFORWARDROW row; - DWORD ret = NO_ERROR, count = 16, table_size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] ); - - TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags); - - if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER; - - if (!(table = HeapAlloc( heap, flags, table_size ))) - return ERROR_OUTOFMEMORY; - - table->dwNumEntries = 0; - -#ifdef __linux__ - { - FILE *fp; - - if ((fp = fopen("/proc/net/route", "r"))) - { - char buf[512], *ptr; - DWORD rtf_flags; - - /* skip header line */ - ptr = fgets(buf, sizeof(buf), fp); - while ((ptr = fgets(buf, sizeof(buf), fp))) - { - memset( &row, 0, sizeof(row) ); - - while (!isspace(*ptr)) ptr++; - *ptr++ = 0; - if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR) - continue; - - row.dwForwardDest = strtoul(ptr, &ptr, 16); - row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16); - rtf_flags = strtoul(ptr + 1, &ptr, 16); - - if (!(rtf_flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID; - else if (rtf_flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT; - else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT; - - strtoul(ptr + 1, &ptr, 16); /* refcount, skip */ - strtoul(ptr + 1, &ptr, 16); /* use, skip */ - row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16); - row.dwForwardMask = strtoul(ptr + 1, &ptr, 16); - /* FIXME: other protos might be appropriate, e.g. the default - * route is typically set with MIB_IPPROTO_NETMGMT instead */ - row.u2.ForwardProto = MIB_IPPROTO_LOCAL; - - if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) ))) - break; - } - fclose(fp); - } - else ret = ERROR_NOT_SUPPORTED; - } -#elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK) - { - void *data; - int fd, len, namelen; - mib2_ipRouteEntry_t *entry; - char name[64]; - - if ((fd = open_streams_mib( NULL )) != -1) - { - if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len ))) - { - for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++) - { - row.dwForwardDest = entry->ipRouteDest; - row.dwForwardMask = entry->ipRouteMask; - row.dwForwardPolicy = 0; - row.dwForwardNextHop = entry->ipRouteNextHop; - row.u1.dwForwardType = entry->ipRouteType; - row.u2.dwForwardProto = entry->ipRouteProto; - row.dwForwardAge = entry->ipRouteAge; - row.dwForwardNextHopAS = 0; - row.dwForwardMetric1 = entry->ipRouteMetric1; - row.dwForwardMetric2 = entry->ipRouteMetric2; - row.dwForwardMetric3 = entry->ipRouteMetric3; - row.dwForwardMetric4 = entry->ipRouteMetric4; - row.dwForwardMetric5 = entry->ipRouteMetric5; - namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length ); - memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen ); - name[namelen] = 0; - getInterfaceIndexByName( name, &row.dwForwardIfIndex ); - if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) ))) - break; - } - HeapFree( GetProcessHeap(), 0, data ); - } - close( fd ); - } - else ret = ERROR_NOT_SUPPORTED; - } -#elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) - { - int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0}; - size_t needed; - char *buf = NULL, *lim, *next, *addrPtr; - struct rt_msghdr *rtm; - - if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) - { - ERR ("sysctl 1 failed!\n"); - ret = ERROR_NOT_SUPPORTED; - goto done; - } - - buf = HeapAlloc (GetProcessHeap (), 0, needed); - if (!buf) - { - ret = ERROR_OUTOFMEMORY; - goto done; - } - - if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) - { - ret = ERROR_NOT_SUPPORTED; - goto done; - } - - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) - { - int i; - sa_family_t dst_family = AF_UNSPEC; - - rtm = (struct rt_msghdr *)next; - - if (rtm->rtm_type != RTM_GET) - { - WARN ("Got unexpected message type 0x%x!\n", - rtm->rtm_type); - continue; - } - - /* Ignore gateway routes which are multicast */ - if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST)) - continue; - - memset( &row, 0, sizeof(row) ); - row.dwForwardIfIndex = rtm->rtm_index; - row.u1.ForwardType = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT; - row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount; - row.u2.ForwardProto = MIB_IPPROTO_LOCAL; - - addrPtr = (char *)(rtm + 1); - - for (i = 1; i; i <<= 1) - { - struct sockaddr *sa; - DWORD addr; - - if (!(i & rtm->rtm_addrs)) - continue; - - sa = (struct sockaddr *)addrPtr; - if (addrPtr + sa->sa_len > next + rtm->rtm_msglen) - { - ERR ("struct sockaddr extends beyond the route message, %p > %p\n", - addrPtr + sa->sa_len, next + rtm->rtm_msglen ); - } - - ADVANCE (addrPtr, sa); - - /* Apple's netstat prints the netmask together with the destination - * and only looks at the destination's address family. The netmask's - * sa_family sometimes contains the non-existent value 0xff. */ - switch(i == RTA_NETMASK ? dst_family : sa->sa_family) { - case AF_INET: { - /* Netmasks (and possibly other addresses) have only enough size - * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has - * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first - * byte of sin_addr). Due to the alignment constraint we can de - * facto read the full 4 bytes of sin_addr (except for the case of - * netmask 0). Don't assume though that the extra bytes are zeroed. */ - struct sockaddr_in sin = {0}; - memcpy(&sin, sa, sa->sa_len); - addr = sin.sin_addr.s_addr; - break; - } -#ifdef AF_LINK - case AF_LINK: - if(i == RTA_GATEWAY && row.u1.ForwardType == MIB_IPROUTE_TYPE_DIRECT) { - /* For direct route we may simply use dest addr as next hop */ - C_ASSERT(RTA_DST < RTA_GATEWAY); - addr = row.dwForwardDest; - break; - } - /* fallthrough */ -#endif - default: - WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family); - addr = 0; - } - - switch (i) - { - case RTA_DST: - row.dwForwardDest = addr; - dst_family = sa->sa_family; - break; - case RTA_GATEWAY: row.dwForwardNextHop = addr; break; - case RTA_NETMASK: row.dwForwardMask = addr; break; - default: - WARN ("Unexpected address type 0x%x\n", i); - } - } - - if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) ))) - break; - } -done: - HeapFree( GetProcessHeap (), 0, buf ); - } -#else - FIXME( "not implemented\n" ); - ret = ERROR_NOT_SUPPORTED; -#endif - - if (!table) return ERROR_OUTOFMEMORY; - if (!ret) - { - if (bOrder && table->dwNumEntries) - qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows ); - *ppIpForwardTable = table; - } - else HeapFree( heap, flags, table ); - TRACE( "returning ret %u table %p\n", ret, table ); - return ret; -} - static int compare_ipnet_rows(const void *a, const void *b) { const MIB_IPNETROW *rowA = a;