nsiproxy: Add support for IPv6 scope ids.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-08-17 09:27:13 +01:00 committed by Alexandre Julliard
parent 14fc764756
commit 40a60061d7
2 changed files with 132 additions and 6 deletions

View File

@ -916,14 +916,12 @@ todo_wine_if( !unstable(0) && row->dwOwningPid )
{
ok( unstable( !memcmp( row6->ucLocalAddr, keys[i].local.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
"mismatch\n" );
todo_wine_if( !unstable(0) && row6->dwLocalScopeId )
ok( unstable( row6->dwLocalScopeId == keys[i].local.Ipv6.sin6_scope_id ), "%x vs %x\n",
row6->dwLocalScopeId, keys[i].local.Ipv6.sin6_scope_id );
ok( unstable( row6->dwLocalPort == keys[i].local.Ipv6.sin6_port ), "%d vs %d\n",
row6->dwLocalPort, keys[i].local.Ipv6.sin6_port );
ok( unstable( !memcmp( row6->ucRemoteAddr, keys[i].remote.Ipv6.sin6_addr.s6_addr, sizeof(IN6_ADDR) ) ),
"mismatch\n" );
todo_wine_if( !unstable(0) && row6->dwRemoteScopeId )
ok( unstable( row6->dwRemoteScopeId == keys[i].remote.Ipv6.sin6_scope_id ), "%x vs %x\n",
row6->dwRemoteScopeId, keys[i].remote.Ipv6.sin6_scope_id );
ok( unstable( row6->dwRemotePort == keys[i].remote.Ipv6.sin6_port ), "%d vs %d\n",

View File

@ -54,6 +54,10 @@
#include <sys/sysctl.h>
#endif
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
@ -209,6 +213,119 @@ static inline MIB_TCP_STATE tcp_state_to_mib_state( int state )
}
}
struct ipv6_addr_scope
{
IN6_ADDR addr;
DWORD scope;
};
static struct ipv6_addr_scope *get_ipv6_addr_scope_table( unsigned int *size )
{
struct ipv6_addr_scope *table = NULL;
unsigned int table_size = 0, num = 0;
#ifdef __linux__
{
char buf[512], *ptr;
FILE *fp;
if (!(fp = fopen( "/proc/net/if_inet6", "r" ))) goto failed;
while ((ptr = fgets( buf, sizeof(buf), fp )))
{
WORD a[8];
DWORD scope;
struct ipv6_addr_scope *entry;
unsigned int i;
if (sscanf( ptr, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
a, a + 1, a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, &scope ) != 9)
continue;
if (++num > table_size)
{
if (!table_size) table_size = 4;
else table_size *= 2;
if (!(table = heap_realloc( table, table_size * sizeof(table[0]) )))
{
fclose( fp );
goto failed;
}
}
entry = table + num - 1;
for (i = 0; i < 8; i++)
entry->addr.u.Word[i] = htons( a[i] );
entry->scope = htons( scope );
}
fclose( fp );
}
#elif defined(HAVE_GETIFADDRS)
{
struct ifaddrs *addrs, *cur;
if (getifaddrs( &addrs ) == -1) goto failed;
for (cur = addrs; cur; cur = cur->ifa_next)
{
struct sockaddr_in6 *sin6;
struct ipv6_addr_scope *entry;
if (cur->ifa_addr->sa_family != AF_INET6) continue;
if (++num > table_size)
{
if (!table_size) table_size = 4;
else table_size *= 2;
if (!(table = heap_realloc( table, table_size * sizeof(table[0]) )))
{
freeifaddrs( addrs );
goto failed;
}
}
sin6 = (struct sockaddr_in6 *)cur->ifa_addr;
entry = table + num - 1;
memcpy( &entry->addr, &sin6->sin6_addr, sizeof(entry->addr) );
entry->scope = sin6->sin6_scope_id;
}
freeifaddrs( addrs );
}
#else
FIXME( "not implemented\n" );
goto failed;
#endif
*size = num;
return table;
failed:
heap_free( table );
return NULL;
}
static DWORD find_ipv6_addr_scope( const IN6_ADDR *addr, const struct ipv6_addr_scope *table, unsigned int size )
{
const BYTE multicast_scope_mask = 0x0F;
const BYTE multicast_scope_shift = 0;
unsigned int i;
if (WS_IN6_IS_ADDR_UNSPECIFIED( addr )) return 0;
if (WS_IN6_IS_ADDR_MULTICAST( addr ))
return htons( (addr->u.Byte[1] & multicast_scope_mask) >> multicast_scope_shift );
if (!table) return -1;
for (i = 0; i < size; i++)
if (!memcmp( &table[i].addr, addr, sizeof(table[i].addr) ))
return table[i].scope;
return -1;
}
static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *key_data, DWORD key_size,
void *rw, DWORD rw_size,
struct nsi_tcp_conn_dynamic *dynamic_data, DWORD dynamic_size,
@ -220,6 +337,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
struct nsi_tcp_conn_key key;
struct nsi_tcp_conn_dynamic dyn;
struct nsi_tcp_conn_static stat;
struct ipv6_addr_scope *addr_scopes = NULL;
unsigned int addr_scopes_size = 0;
#ifdef __linux__
{
@ -269,6 +388,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
memset( &dyn, 0, sizeof(dyn) );
memset( &stat, 0, sizeof(stat) );
addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
/* skip header line */
ptr = fgets( buf, sizeof(buf), fp );
while ((ptr = fgets( buf, sizeof(buf), fp )))
@ -286,8 +407,10 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
key.local.Ipv6.sin6_port = htons( key.local.Ipv6.sin6_port );
key.remote.Ipv6.sin6_port = htons( key.remote.Ipv6.sin6_port );
key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes,
addr_scopes_size );
key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes,
addr_scopes_size );
stat.pid = 0; /* FIXME */
stat.create_time = 0; /* FIXME */
@ -335,6 +458,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
/* Might be nothing here; first entry is just a header it seems */
if (len <= sizeof(struct xinpgen)) goto err;
addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
orig_xig = (struct xinpgen *)buf;
xig = orig_xig;
@ -384,10 +509,12 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv6.sin6_family = key.remote.Ipv6.sin6_family = WS_AF_INET6;
memcpy( &key.local.Ipv6.sin6_addr, &in->in6p_laddr, sizeof(in->in6p_laddr) );
key.local.Ipv6.sin6_port = in->inp_lport;
key.local.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.local.Ipv6.sin6_addr, addr_scopes,
addr_scopes_size );
memcpy( &key.remote.Ipv6.sin6_addr, &in->in6p_faddr, sizeof(in->in6p_faddr) );
key.remote.Ipv6.sin6_port = in->inp_fport;
key.local.Ipv6.sin6_scope_id = 0; /* FIXME */
key.remote.Ipv6.sin6_scope_id = 0; /* FIXME */
key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes,
addr_scopes_size );
}
stat.pid = 0; /* FIXME */
@ -413,6 +540,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
if (!want_data || num <= *count) *count = num;
else status = STATUS_MORE_ENTRIES;
heap_free( addr_scopes );
return status;
}