iphlpapi: Implement AllocateAndGetTcp(Ex)TableFromStack() on top of nsi.
Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f535ab7197
commit
7341bee1dc
|
@ -3240,6 +3240,49 @@ ULONG WINAPI GetTcp6Table2( MIB_TCP6TABLE2 *table, ULONG *size, BOOL sort )
|
||||||
return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE2 );
|
return get_extended_tcp_table( table, size, sort, WS_AF_INET6, TCP_TABLE2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD allocate_tcp_table( void **table, BOOL sort, HANDLE heap, DWORD flags,
|
||||||
|
ULONG family, ULONG table_class )
|
||||||
|
{
|
||||||
|
DWORD err, size = 0x100, attempt;
|
||||||
|
|
||||||
|
for (attempt = 0; attempt < 5; attempt++)
|
||||||
|
{
|
||||||
|
*table = HeapAlloc( heap, flags, size );
|
||||||
|
if (!*table) return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
err = get_extended_tcp_table( *table, &size, sort, family, table_class );
|
||||||
|
if (!err) break;
|
||||||
|
HeapFree( heap, flags, *table );
|
||||||
|
*table = NULL;
|
||||||
|
if (err != ERROR_INSUFFICIENT_BUFFER) break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI AllocateAndGetTcpTableFromStack( MIB_TCPTABLE **table, BOOL sort, HANDLE heap, DWORD flags )
|
||||||
|
{
|
||||||
|
TRACE( "table %p, sort %d, heap %p, flags 0x%08x\n", table, sort, heap, flags );
|
||||||
|
|
||||||
|
if (!table) return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
return allocate_tcp_table( (void **)table, sort, heap, flags, WS_AF_INET, TCP_TABLE_BASIC_ALL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI AllocateAndGetTcpExTableFromStack( void **table, BOOL sort, HANDLE heap, DWORD flags, DWORD family )
|
||||||
|
{
|
||||||
|
TRACE( "table %p, sort %d, heap %p, flags 0x%08x, family %u\n", table, sort, heap, flags, family );
|
||||||
|
|
||||||
|
if (!table || !ip_module_id( family )) return ERROR_INVALID_PARAMETER;
|
||||||
|
if (family == WS_AF_INET6) return ERROR_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
return allocate_tcp_table( table, sort, heap, flags, family, TCP_TABLE_OWNER_PID_ALL );
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* GetUdpTable (IPHLPAPI.@)
|
* GetUdpTable (IPHLPAPI.@)
|
||||||
*
|
*
|
||||||
|
|
|
@ -466,77 +466,6 @@ static void *append_table_row( HANDLE heap, DWORD flags, void *table, DWORD *tab
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
|
||||||
{
|
|
||||||
DWORD table_size;
|
|
||||||
|
|
||||||
switch (class)
|
|
||||||
{
|
|
||||||
case TCP_TABLE_BASIC_LISTENER:
|
|
||||||
case TCP_TABLE_BASIC_CONNECTIONS:
|
|
||||||
case TCP_TABLE_BASIC_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCPROW);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TCP_TABLE_OWNER_PID_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_PID_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_PID_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TCP_TABLE_OWNER_MODULE_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_MODULE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ERR("unhandled class %u\n", class);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return table_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Why not a lookup table? Because the TCPS_* constants are different
|
|
||||||
on different platforms */
|
|
||||||
static inline MIB_TCP_STATE TCPStateToMIBState (int state)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
|
|
||||||
case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
|
|
||||||
case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
|
|
||||||
case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
|
|
||||||
case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
|
|
||||||
case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
|
|
||||||
case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
|
|
||||||
case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
|
|
||||||
case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
|
|
||||||
case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
|
|
||||||
default:
|
|
||||||
case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_tcp_rows(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const MIB_TCPROW *rowA = a;
|
|
||||||
const MIB_TCPROW *rowB = b;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
|
|
||||||
if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
|
|
||||||
ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
|
|
||||||
if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
|
|
||||||
return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pid_map
|
struct pid_map
|
||||||
{
|
{
|
||||||
unsigned int pid;
|
unsigned int pid;
|
||||||
|
@ -715,289 +644,6 @@ static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entri
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL match_class( TCP_TABLE_CLASS class, MIB_TCP_STATE state )
|
|
||||||
{
|
|
||||||
switch (class)
|
|
||||||
{
|
|
||||||
case TCP_TABLE_BASIC_ALL:
|
|
||||||
case TCP_TABLE_OWNER_PID_ALL:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_ALL:
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
case TCP_TABLE_BASIC_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_PID_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_LISTENER:
|
|
||||||
if (state == MIB_TCP_STATE_LISTEN) return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
case TCP_TABLE_BASIC_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_PID_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
|
|
||||||
if (state == MIB_TCP_STATE_ESTAB) return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERR( "unhandled class %u\n", class );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
|
|
||||||
DWORD *size )
|
|
||||||
{
|
|
||||||
MIB_TCPTABLE *table;
|
|
||||||
MIB_TCPROW_OWNER_MODULE row;
|
|
||||||
DWORD ret = NO_ERROR, count = 16, table_size, row_size;
|
|
||||||
|
|
||||||
if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
|
|
||||||
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/tcp", "r")))
|
|
||||||
{
|
|
||||||
char buf[512], *ptr;
|
|
||||||
struct pid_map *map = NULL;
|
|
||||||
unsigned int num_entries = 0;
|
|
||||||
int inode;
|
|
||||||
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
|
|
||||||
|
|
||||||
/* skip header line */
|
|
||||||
ptr = fgets(buf, sizeof(buf), fp);
|
|
||||||
while ((ptr = fgets(buf, sizeof(buf), fp)))
|
|
||||||
{
|
|
||||||
if (sscanf( ptr, "%*x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d",
|
|
||||||
&row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
|
|
||||||
&row.dwRemotePort, &row.dwState, &inode ) != 6)
|
|
||||||
continue;
|
|
||||||
row.dwLocalPort = htons( row.dwLocalPort );
|
|
||||||
row.dwRemotePort = htons( row.dwRemotePort );
|
|
||||||
row.dwState = TCPStateToMIBState( row.dwState );
|
|
||||||
if (!match_class( class, row.dwState )) continue;
|
|
||||||
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER)
|
|
||||||
row.dwOwningPid = find_owning_pid( map, num_entries, inode );
|
|
||||||
if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
|
|
||||||
{
|
|
||||||
row.liCreateTimestamp.QuadPart = 0; /* FIXME */
|
|
||||||
memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
|
|
||||||
}
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, map );
|
|
||||||
fclose( fp );
|
|
||||||
}
|
|
||||||
else ret = ERROR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
int fd, len;
|
|
||||||
mib2_tcpConnEntry_t *entry;
|
|
||||||
|
|
||||||
if ((fd = open_streams_mib( "tcp" )) != -1)
|
|
||||||
{
|
|
||||||
if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
|
|
||||||
{
|
|
||||||
for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
|
|
||||||
{
|
|
||||||
row.dwLocalAddr = entry->tcpConnLocalAddress;
|
|
||||||
row.dwLocalPort = htons( entry->tcpConnLocalPort );
|
|
||||||
row.dwRemoteAddr = entry->tcpConnRemAddress;
|
|
||||||
row.dwRemotePort = htons( entry->tcpConnRemPort );
|
|
||||||
row.dwState = entry->tcpConnState;
|
|
||||||
if (!match_class( class, row.dwState )) continue;
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, data );
|
|
||||||
}
|
|
||||||
close( fd );
|
|
||||||
}
|
|
||||||
else ret = ERROR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
|
|
||||||
{
|
|
||||||
size_t Len = 0;
|
|
||||||
char *Buf = NULL;
|
|
||||||
struct xinpgen *pXIG, *pOrigXIG;
|
|
||||||
struct pid_map *pMap = NULL;
|
|
||||||
unsigned NumEntries;
|
|
||||||
|
|
||||||
if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
|
|
||||||
{
|
|
||||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
Buf = HeapAlloc (GetProcessHeap (), 0, Len);
|
|
||||||
if (!Buf)
|
|
||||||
{
|
|
||||||
ret = ERROR_OUTOFMEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
|
|
||||||
{
|
|
||||||
ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER) pMap = get_pid_map( &NumEntries );
|
|
||||||
|
|
||||||
/* Might be nothing here; first entry is just a header it seems */
|
|
||||||
if (Len <= sizeof (struct xinpgen)) goto done;
|
|
||||||
|
|
||||||
pOrigXIG = (struct xinpgen *)Buf;
|
|
||||||
pXIG = pOrigXIG;
|
|
||||||
|
|
||||||
for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
|
|
||||||
pXIG->xig_len > sizeof (struct xinpgen);
|
|
||||||
pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
|
|
||||||
{
|
|
||||||
#if __FreeBSD_version >= 1200026
|
|
||||||
struct xtcpcb *pTCPData = (struct xtcpcb *)pXIG;
|
|
||||||
struct xinpcb *pINData = &pTCPData->xt_inp;
|
|
||||||
struct xsocket *pSockData = &pINData->xi_socket;
|
|
||||||
#else
|
|
||||||
struct tcpcb *pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
|
|
||||||
struct inpcb *pINData = &((struct xtcpcb *)pXIG)->xt_inp;
|
|
||||||
struct xsocket *pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Ignore sockets for other protocols */
|
|
||||||
if (pSockData->xso_protocol != IPPROTO_TCP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Ignore PCBs that were freed while generating the data */
|
|
||||||
if (pINData->inp_gencnt > pOrigXIG->xig_gen)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* we're only interested in IPv4 addresses */
|
|
||||||
if (!(pINData->inp_vflag & INP_IPV4) ||
|
|
||||||
(pINData->inp_vflag & INP_IPV6))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* If all 0's, skip it */
|
|
||||||
if (!pINData->inp_laddr.s_addr &&
|
|
||||||
!pINData->inp_lport &&
|
|
||||||
!pINData->inp_faddr.s_addr &&
|
|
||||||
!pINData->inp_fport)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Fill in structure details */
|
|
||||||
row.dwLocalAddr = pINData->inp_laddr.s_addr;
|
|
||||||
row.dwLocalPort = pINData->inp_lport;
|
|
||||||
row.dwRemoteAddr = pINData->inp_faddr.s_addr;
|
|
||||||
row.dwRemotePort = pINData->inp_fport;
|
|
||||||
row.dwState = TCPStateToMIBState (pTCPData->t_state);
|
|
||||||
if (!match_class( class, row.dwState )) continue;
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER)
|
|
||||||
row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
|
|
||||||
if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
|
|
||||||
{
|
|
||||||
row.liCreateTimestamp.QuadPart = 0; /* FIXME */
|
|
||||||
memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
|
|
||||||
}
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
HeapFree( GetProcessHeap(), 0, pMap );
|
|
||||||
HeapFree (GetProcessHeap (), 0, Buf);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
FIXME( "not implemented\n" );
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!table) return ERROR_OUTOFMEMORY;
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
if (order && table->dwNumEntries)
|
|
||||||
qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
|
|
||||||
*tablep = table;
|
|
||||||
}
|
|
||||||
else HeapFree( heap, flags, table );
|
|
||||||
if (size) *size = get_tcp_table_sizes( class, count, NULL );
|
|
||||||
TRACE( "returning ret %u table %p\n", ret, table );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************
|
|
||||||
* AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
|
|
||||||
*
|
|
||||||
* Get the TCP connection table.
|
|
||||||
* Like GetTcpTable(), but allocate the returned table from heap.
|
|
||||||
*
|
|
||||||
* PARAMS
|
|
||||||
* ppTcpTable [Out] pointer into which the MIB_TCPTABLE 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 ppTcpTable is NULL, whatever GetTcpTable()
|
|
||||||
* returns otherwise.
|
|
||||||
*/
|
|
||||||
DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
|
|
||||||
HANDLE heap, DWORD flags )
|
|
||||||
{
|
|
||||||
TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
|
|
||||||
|
|
||||||
if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
|
|
||||||
return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************
|
|
||||||
* AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
|
|
||||||
*
|
|
||||||
* Get the TCP connection table.
|
|
||||||
* Like GetTcpTable(), but allocate the returned table from heap.
|
|
||||||
*
|
|
||||||
* PARAMS
|
|
||||||
* ppTcpTable [Out] pointer into which the MIB_TCPTABLE_EX 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
|
|
||||||
* family [In] address family [AF_INET|AF_INET6]
|
|
||||||
*
|
|
||||||
* RETURNS
|
|
||||||
* ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
|
|
||||||
* returns otherwise.
|
|
||||||
*/
|
|
||||||
DWORD WINAPI AllocateAndGetTcpExTableFromStack( VOID **ppTcpTable, BOOL bOrder,
|
|
||||||
HANDLE heap, DWORD flags, DWORD family )
|
|
||||||
{
|
|
||||||
TRACE("table %p, bOrder %d, heap %p, flags 0x%08x, family %u\n",
|
|
||||||
ppTcpTable, bOrder, heap, flags, family);
|
|
||||||
|
|
||||||
if (!ppTcpTable || !family)
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
if (family != WS_AF_INET)
|
|
||||||
{
|
|
||||||
FIXME( "family = %u not supported\n", family );
|
|
||||||
return ERROR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return build_tcp_table( TCP_TABLE_OWNER_PID_ALL, ppTcpTable, bOrder, heap, flags, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
||||||
{
|
{
|
||||||
DWORD table_size;
|
DWORD table_size;
|
||||||
|
@ -1222,71 +868,6 @@ DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD get_tcp6_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
|
||||||
{
|
|
||||||
DWORD table_size;
|
|
||||||
|
|
||||||
switch (class)
|
|
||||||
{
|
|
||||||
case TCP_TABLE_BASIC_LISTENER:
|
|
||||||
case TCP_TABLE_BASIC_CONNECTIONS:
|
|
||||||
case TCP_TABLE_BASIC_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCP6ROW);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TCP_TABLE_OWNER_PID_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_PID_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_PID_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_PID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TCP_TABLE_OWNER_MODULE_LISTENER:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
|
|
||||||
case TCP_TABLE_OWNER_MODULE_ALL:
|
|
||||||
{
|
|
||||||
table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
|
|
||||||
if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_MODULE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ERR("unhandled class %u\n", class);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return table_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_tcp6_basic_rows(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const MIB_TCP6ROW *rowA = a;
|
|
||||||
const MIB_TCP6ROW *rowB = b;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = memcmp(&rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr))) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
|
|
||||||
if ((ret = memcmp(&rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr))) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
|
|
||||||
return rowA->dwRemotePort - rowB->dwRemotePort;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_tcp6_owner_rows(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const MIB_TCP6ROW_OWNER_PID *rowA = a;
|
|
||||||
const MIB_TCP6ROW_OWNER_PID *rowB = b;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = memcmp(&rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr))) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
|
|
||||||
if ((ret = memcmp(&rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr))) != 0) return ret;
|
|
||||||
if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
|
|
||||||
return rowA->dwRemotePort - rowB->dwRemotePort;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
|
||||||
{
|
{
|
||||||
DWORD table_size;
|
DWORD table_size;
|
||||||
|
@ -1456,231 +1037,6 @@ static DWORD find_ipv6_addr_scope(const IN6_ADDR *addr, const struct ipv6_addr_s
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DWORD build_tcp6_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
|
|
||||||
DWORD *size )
|
|
||||||
{
|
|
||||||
MIB_TCP6TABLE *table;
|
|
||||||
DWORD ret = NO_ERROR, count = 16, table_size, row_size;
|
|
||||||
|
|
||||||
if (!(table_size = get_tcp6_table_sizes( class, count, &row_size )))
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
if (!(table = HeapAlloc( heap, flags, table_size )))
|
|
||||||
return ERROR_OUTOFMEMORY;
|
|
||||||
|
|
||||||
table->dwNumEntries = 0;
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
{
|
|
||||||
MIB_TCP6ROW_OWNER_MODULE row;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if ((fp = fopen( "/proc/net/tcp6", "r" )))
|
|
||||||
{
|
|
||||||
char buf[512], *ptr;
|
|
||||||
struct pid_map *map = NULL;
|
|
||||||
unsigned int num_entries = 0;
|
|
||||||
struct ipv6_addr_scope *addr_scopes;
|
|
||||||
unsigned int addr_scopes_size = 0;
|
|
||||||
int inode;
|
|
||||||
|
|
||||||
addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
|
|
||||||
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
|
|
||||||
|
|
||||||
/* skip header line */
|
|
||||||
ptr = fgets( buf, sizeof(buf), fp );
|
|
||||||
while ((ptr = fgets( buf, sizeof(buf), fp )))
|
|
||||||
{
|
|
||||||
DWORD *local_addr = (DWORD *)&row.ucLocalAddr;
|
|
||||||
DWORD *remote_addr = (DWORD *)&row.ucRemoteAddr;
|
|
||||||
|
|
||||||
if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %*s %*s %*s %*s %*s %*s %*s %d",
|
|
||||||
&local_addr[0], &local_addr[1], &local_addr[2], &local_addr[3], &row.dwLocalPort,
|
|
||||||
&remote_addr[0], &remote_addr[1], &remote_addr[2], &remote_addr[3], &row.dwRemotePort,
|
|
||||||
&row.dwState, &inode ) != 12)
|
|
||||||
continue;
|
|
||||||
row.dwState = TCPStateToMIBState( row.dwState );
|
|
||||||
if (!match_class( class, row.dwState )) continue;
|
|
||||||
row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
|
|
||||||
row.dwLocalPort = htons( row.dwLocalPort );
|
|
||||||
row.dwRemoteScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size);
|
|
||||||
row.dwRemotePort = htons( row.dwRemotePort );
|
|
||||||
|
|
||||||
if (class <= TCP_TABLE_BASIC_ALL)
|
|
||||||
{
|
|
||||||
/* MIB_TCP6ROW has a different field order */
|
|
||||||
MIB_TCP6ROW basic_row;
|
|
||||||
basic_row.State = row.dwState;
|
|
||||||
memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
|
|
||||||
basic_row.dwLocalScopeId = row.dwLocalScopeId;
|
|
||||||
basic_row.dwLocalPort = row.dwLocalPort;
|
|
||||||
memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
|
|
||||||
basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
|
|
||||||
basic_row.dwRemotePort = row.dwRemotePort;
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
row.dwOwningPid = find_owning_pid( map, num_entries, inode );
|
|
||||||
if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
|
|
||||||
{
|
|
||||||
row.liCreateTimestamp.QuadPart = 0; /* FIXME */
|
|
||||||
memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
|
|
||||||
}
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, map );
|
|
||||||
HeapFree( GetProcessHeap(), 0, addr_scopes );
|
|
||||||
fclose( fp );
|
|
||||||
}
|
|
||||||
else ret = ERROR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
|
|
||||||
{
|
|
||||||
static const char zero[sizeof(IN6_ADDR)] = {0};
|
|
||||||
|
|
||||||
MIB_TCP6ROW_OWNER_MODULE row;
|
|
||||||
size_t len = 0;
|
|
||||||
char *buf = NULL;
|
|
||||||
struct xinpgen *xig, *orig_xig;
|
|
||||||
struct pid_map *map = NULL;
|
|
||||||
unsigned num_entries;
|
|
||||||
struct ipv6_addr_scope *addr_scopes = NULL;
|
|
||||||
unsigned int addr_scopes_size = 0;
|
|
||||||
|
|
||||||
if (sysctlbyname( "net.inet.tcp.pcblist", NULL, &len, NULL, 0 ) < 0)
|
|
||||||
{
|
|
||||||
ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = HeapAlloc( GetProcessHeap(), 0, len );
|
|
||||||
if (!buf)
|
|
||||||
{
|
|
||||||
ret = ERROR_OUTOFMEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sysctlbyname( "net.inet.tcp.pcblist", buf, &len, NULL, 0 ) < 0)
|
|
||||||
{
|
|
||||||
ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
|
|
||||||
if (!addr_scopes)
|
|
||||||
{
|
|
||||||
ret = ERROR_OUTOFMEMORY;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
|
|
||||||
|
|
||||||
/* Might be nothing here; first entry is just a header it seems */
|
|
||||||
if (len <= sizeof (struct xinpgen)) goto done;
|
|
||||||
|
|
||||||
orig_xig = (struct xinpgen *)buf;
|
|
||||||
xig = orig_xig;
|
|
||||||
|
|
||||||
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
|
|
||||||
xig->xig_len > sizeof (struct xinpgen);
|
|
||||||
xig = (struct xinpgen *)((char *)xig + xig->xig_len))
|
|
||||||
{
|
|
||||||
#if __FreeBSD_version >= 1200026
|
|
||||||
struct xtcpcb *tcp = (struct xtcpcb *)xig;
|
|
||||||
struct xinpcb *in = &tcp->xt_inp;
|
|
||||||
struct xsocket *sock = &in->xi_socket;
|
|
||||||
#else
|
|
||||||
struct tcpcb *tcp = &((struct xtcpcb *)xig)->xt_tp;
|
|
||||||
struct inpcb *in = &((struct xtcpcb *)xig)->xt_inp;
|
|
||||||
struct xsocket *sock = &((struct xtcpcb *)xig)->xt_socket;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Ignore sockets for other protocols */
|
|
||||||
if (sock->xso_protocol != IPPROTO_TCP)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Ignore PCBs that were freed while generating the data */
|
|
||||||
if (in->inp_gencnt > orig_xig->xig_gen)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* we're only interested in IPv6 addresses */
|
|
||||||
if (!(in->inp_vflag & INP_IPV6) ||
|
|
||||||
(in->inp_vflag & INP_IPV4))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* If all 0's, skip it */
|
|
||||||
if (!memcmp( &in->in6p_laddr, zero, sizeof(zero) ) && !in->inp_lport &&
|
|
||||||
!memcmp( &in->in6p_faddr, zero, sizeof(zero) ) && !in->inp_fport)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Fill in structure details */
|
|
||||||
memcpy( &row.ucLocalAddr, &in->in6p_laddr.s6_addr, sizeof(row.ucLocalAddr) );
|
|
||||||
row.dwLocalPort = in->inp_lport;
|
|
||||||
row.dwLocalScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size );
|
|
||||||
memcpy( &row.ucRemoteAddr, &in->in6p_faddr.s6_addr, sizeof(row.ucRemoteAddr) );
|
|
||||||
row.dwRemotePort = in->inp_fport;
|
|
||||||
row.dwRemoteScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size );
|
|
||||||
row.dwState = TCPStateToMIBState( tcp->t_state );
|
|
||||||
if (!match_class( class, row.dwState )) continue;
|
|
||||||
|
|
||||||
if (class <= TCP_TABLE_BASIC_ALL)
|
|
||||||
{
|
|
||||||
/* MIB_TCP6ROW has a different field order */
|
|
||||||
MIB_TCP6ROW basic_row;
|
|
||||||
basic_row.State = row.dwState;
|
|
||||||
memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
|
|
||||||
basic_row.dwLocalScopeId = row.dwLocalScopeId;
|
|
||||||
basic_row.dwLocalPort = row.dwLocalPort;
|
|
||||||
memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
|
|
||||||
basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
|
|
||||||
basic_row.dwRemotePort = row.dwRemotePort;
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
row.dwOwningPid = find_owning_pid( map, num_entries, (UINT_PTR)sock->so_pcb );
|
|
||||||
if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
|
|
||||||
{
|
|
||||||
row.liCreateTimestamp.QuadPart = 0; /* FIXME */
|
|
||||||
memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
|
|
||||||
}
|
|
||||||
if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
HeapFree( GetProcessHeap(), 0, map );
|
|
||||||
HeapFree( GetProcessHeap(), 0, buf );
|
|
||||||
HeapFree( GetProcessHeap(), 0, addr_scopes );
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
FIXME( "not implemented\n" );
|
|
||||||
ret = ERROR_NOT_SUPPORTED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!table) return ERROR_OUTOFMEMORY;
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
if (order && table->dwNumEntries)
|
|
||||||
{
|
|
||||||
qsort( table->table, table->dwNumEntries, row_size,
|
|
||||||
class <= TCP_TABLE_BASIC_ALL ? compare_tcp6_basic_rows : compare_tcp6_owner_rows );
|
|
||||||
}
|
|
||||||
*tablep = table;
|
|
||||||
}
|
|
||||||
else HeapFree( heap, flags, table );
|
|
||||||
if (size) *size = get_tcp6_table_sizes( class, count, NULL );
|
|
||||||
TRACE( "returning ret %u table %p\n", ret, table );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
|
DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
|
||||||
DWORD *size )
|
DWORD *size )
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "iprtrmib.h"
|
#include "iprtrmib.h"
|
||||||
|
|
||||||
DWORD build_tcp_table(TCP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
|
||||||
DWORD build_tcp6_table(TCP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
|
||||||
DWORD build_udp_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
DWORD build_udp_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
||||||
DWORD build_udp6_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
DWORD build_udp6_table(UDP_TABLE_CLASS, void **, BOOL, HANDLE, DWORD, DWORD *) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue