[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