[PATCH 4/7] nsiproxy: Add support for TCP pid lookup.
Huw Davies
huw at codeweavers.com
Tue Aug 17 03:27:14 CDT 2021
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
dlls/nsi/tests/nsi.c | 2 -
dlls/nsiproxy.sys/tcp.c | 207 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 203 insertions(+), 6 deletions(-)
diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c
index f8ba9aff5da..b5352e2b121 100644
--- a/dlls/nsi/tests/nsi.c
+++ b/dlls/nsi/tests/nsi.c
@@ -906,7 +906,6 @@ static void test_tcp_tables( int family, int table_type )
ok( unstable( row->dwRemotePort == keys[i].remote.Ipv4.sin_port ), "%d vs %d\n",
row->dwRemotePort, keys[i].remote.Ipv4.sin_port );
ok( unstable( row->dwState == dyn->state ), "%x vs %x\n", row->dwState, dyn->state );
-todo_wine_if( !unstable(0) && row->dwOwningPid )
ok( unstable( row->dwOwningPid == stat[i].pid ), "%x vs %x\n", row->dwOwningPid, stat[i].pid );
ok( unstable( row->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
ok( unstable( row->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
@@ -927,7 +926,6 @@ todo_wine_if( !unstable(0) && row->dwOwningPid )
ok( unstable( row6->dwRemotePort == keys[i].remote.Ipv6.sin6_port ), "%d vs %d\n",
row6->dwRemotePort, keys[i].remote.Ipv6.sin6_port );
ok( unstable( row6->dwState == dyn->state ), "%x vs %x\n", row6->dwState, dyn->state );
-todo_wine_if( !unstable(0) && row6->dwOwningPid )
ok( unstable( row6->dwOwningPid == stat[i].pid ), "%x vs %x\n", row6->dwOwningPid, stat[i].pid );
ok( unstable( row6->liCreateTimestamp.QuadPart == stat[i].create_time ), "mismatch\n" );
ok( unstable( row6->OwningModuleInfo[0] == stat[i].mod_info ), "mismatch\n");
diff --git a/dlls/nsiproxy.sys/tcp.c b/dlls/nsiproxy.sys/tcp.c
index 5b4a4b68765..27f85ee3104 100644
--- a/dlls/nsiproxy.sys/tcp.c
+++ b/dlls/nsiproxy.sys/tcp.c
@@ -26,6 +26,14 @@
#include <sys/types.h>
#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
@@ -58,6 +66,14 @@
#include <ifaddrs.h>
#endif
+#ifdef HAVE_LIBPROCSTAT_H
+#include <libprocstat.h>
+#endif
+
+#ifdef HAVE_LIBPROC_H
+#include <libproc.h>
+#endif
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
@@ -72,6 +88,7 @@
#include "wine/heap.h"
#include "wine/nsi.h"
#include "wine/debug.h"
+#include "wine/server.h"
#include "nsiproxy_private.h"
@@ -326,6 +343,184 @@ static DWORD find_ipv6_addr_scope( const IN6_ADDR *addr, const struct ipv6_addr_
return -1;
}
+struct pid_map
+{
+ unsigned int pid;
+ unsigned int unix_pid;
+};
+
+static struct pid_map *get_pid_map( unsigned int *num_entries )
+{
+ struct pid_map *map;
+ unsigned int i = 0, buffer_len = 4096, process_count, pos = 0;
+ NTSTATUS ret;
+ char *buffer = NULL, *new_buffer;
+
+ if (!(buffer = heap_alloc( buffer_len ))) return NULL;
+
+ for (;;)
+ {
+ SERVER_START_REQ( list_processes )
+ {
+ wine_server_set_reply( req, buffer, buffer_len );
+ ret = wine_server_call( req );
+ buffer_len = reply->info_size;
+ process_count = reply->process_count;
+ }
+ SERVER_END_REQ;
+
+ if (ret != STATUS_INFO_LENGTH_MISMATCH) break;
+
+ if (!(new_buffer = heap_realloc( buffer, buffer_len )))
+ {
+ heap_free( buffer );
+ return NULL;
+ }
+ buffer = new_buffer;
+ }
+
+ if (!(map = heap_alloc( process_count * sizeof(*map) )))
+ {
+ heap_free( buffer );
+ return NULL;
+ }
+
+ for (i = 0; i < process_count; ++i)
+ {
+ const struct process_info *process;
+
+ pos = (pos + 7) & ~7;
+ process = (const struct process_info *)(buffer + pos);
+
+ map[i].pid = process->pid;
+ map[i].unix_pid = process->unix_pid;
+
+ pos += sizeof(struct process_info) + process->name_len;
+ pos = (pos + 7) & ~7;
+ pos += process->thread_count * sizeof(struct thread_info);
+ }
+
+ heap_free( buffer );
+ *num_entries = process_count;
+ return map;
+}
+
+static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UINT_PTR inode )
+{
+#ifdef __linux__
+ unsigned int i, len_socket;
+ char socket[32];
+
+ sprintf( socket, "socket:[%lu]", inode );
+ len_socket = strlen( socket );
+ for (i = 0; i < num_entries; i++)
+ {
+ char dir[32];
+ struct dirent *dirent;
+ DIR *dirfd;
+
+ sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
+ if ((dirfd = opendir( dir )))
+ {
+ while ((dirent = readdir( dirfd )))
+ {
+ char link[sizeof(dirent->d_name) + 32], name[32];
+ int len;
+
+ sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
+ if ((len = readlink( link, name, sizeof(name) - 1 )) > 0) name[len] = 0;
+ if (len == len_socket && !strcmp( socket, name ))
+ {
+ closedir( dirfd );
+ return map[i].pid;
+ }
+ }
+ closedir( dirfd );
+ }
+ }
+ return 0;
+#elif defined(HAVE_LIBPROCSTAT)
+ struct procstat *pstat;
+ struct kinfo_proc *proc;
+ struct filestat_list *fds;
+ struct filestat *fd;
+ struct sockstat sock;
+ unsigned int i, proc_count;
+
+ pstat = procstat_open_sysctl();
+ if (!pstat) return 0;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ proc = procstat_getprocs( pstat, KERN_PROC_PID, map[i].unix_pid, &proc_count );
+ if (!proc || proc_count < 1) continue;
+
+ fds = procstat_getfiles( pstat, proc, 0 );
+ if (!fds)
+ {
+ procstat_freeprocs( pstat, proc );
+ continue;
+ }
+
+ STAILQ_FOREACH( fd, fds, next )
+ {
+ char errbuf[_POSIX2_LINE_MAX];
+
+ if (fd->fs_type != PS_FST_TYPE_SOCKET) continue;
+
+ procstat_get_socket_info( pstat, fd, &sock, errbuf );
+
+ if (sock.so_pcb == inode)
+ {
+ procstat_freefiles( pstat, fds );
+ procstat_freeprocs( pstat, proc );
+ procstat_close( pstat );
+ return map[i].pid;
+ }
+ }
+
+ procstat_freefiles( pstat, fds );
+ procstat_freeprocs( pstat, proc );
+ }
+
+ procstat_close( pstat );
+ return 0;
+#elif defined(HAVE_PROC_PIDINFO)
+ struct proc_fdinfo *fds;
+ struct socket_fdinfo sock;
+ unsigned int i, j, n;
+
+ for (i = 0; i < num_entries; i++)
+ {
+ int fd_len = proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, NULL, 0 );
+ if (fd_len <= 0) continue;
+
+ fds = heap_alloc( fd_len );
+ if (!fds) continue;
+
+ proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, fds, fd_len );
+ n = fd_len / sizeof(struct proc_fdinfo);
+ for (j = 0; j < n; j++)
+ {
+ if (fds[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue;
+
+ proc_pidfdinfo( map[i].unix_pid, fds[j].proc_fd, PROC_PIDFDSOCKETINFO, &sock, sizeof(sock) );
+ if (sock.psi.soi_pcb == inode)
+ {
+ heap_free( fds );
+ return map[i].pid;
+ }
+ }
+
+ heap_free( fds );
+ }
+ return 0;
+#else
+ FIXME( "not implemented\n" );
+ return 0;
+#endif
+}
+
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,
@@ -338,7 +533,8 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_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;
+ unsigned int addr_scopes_size = 0, pid_map_size = 0;
+ struct pid_map *pid_map = NULL;
#ifdef __linux__
{
@@ -351,6 +547,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
memset( &key, 0, sizeof(key) );
memset( &dyn, 0, sizeof(dyn) );
memset( &stat, 0, sizeof(stat) );
+ pid_map = get_pid_map( &pid_map_size );
/* skip header line */
ptr = fgets( buf, sizeof(buf), fp );
@@ -368,7 +565,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
key.local.Ipv4.sin_port = htons( key.local.Ipv4.sin_port );
key.remote.Ipv4.sin_port = htons( key.remote.Ipv4.sin_port );
- stat.pid = 0; /* FIXME */
+ stat.pid = find_owning_pid( pid_map, pid_map_size, inode );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -412,7 +609,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
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.pid = find_owning_pid( pid_map, pid_map_size, inode );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -459,6 +656,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
if (len <= sizeof(struct xinpgen)) goto err;
addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
+ pid_map = get_pid_map( &pid_map_size );
orig_xig = (struct xinpgen *)buf;
xig = orig_xig;
@@ -517,7 +715,7 @@ static NTSTATUS tcp_conns_enumerate_all( DWORD filter, struct nsi_tcp_conn_key *
addr_scopes_size );
}
- stat.pid = 0; /* FIXME */
+ stat.pid = find_owning_pid( pid_map, pid_map_size, (UINT_PTR)sock->so_pcb );
stat.create_time = 0; /* FIXME */
stat.mod_info = 0; /* FIXME */
@@ -540,6 +738,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( pid_map );
heap_free( addr_scopes );
return status;
}
--
2.23.0
More information about the wine-devel
mailing list