iphlpapi: Implement AllocateAndGetIpForwardTable() on top of GetIpForwardTable().
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0515480d89
commit
413eeaead5
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue