From: Tim Clem tclem@codeweavers.com
--- dlls/nsiproxy.sys/tcp.c | 306 +++++++--------------------------------- server/handle.c | 37 +++++ server/handle.h | 2 + server/protocol.def | 41 ++++++ server/sock.c | 143 +++++++++++++++++++ server/trace.c | 67 +++++++++ tools/make_requests | 1 + 7 files changed, 344 insertions(+), 253 deletions(-)
diff --git a/dlls/nsiproxy.sys/tcp.c b/dlls/nsiproxy.sys/tcp.c index dd8c9d1102a..96d517d1539 100644 --- a/dlls/nsiproxy.sys/tcp.c +++ b/dlls/nsiproxy.sys/tcp.c @@ -43,10 +43,6 @@ #include <netinet/in.h> #endif
-#ifdef HAVE_NETINET_IN_PCB_H -#include <netinet/in_pcb.h> -#endif - #ifdef HAVE_NETINET_IP_VAR_H #include <netinet/ip_var.h> #endif @@ -59,10 +55,6 @@ #include <netinet/tcp_var.h> #endif
-#ifdef HAVE_NETINET_TCP_FSM_H -#include <netinet/tcp_fsm.h> -#endif - #ifdef HAVE_SYS_SYSCTL_H #include <sys/sysctl.h> #endif @@ -96,20 +88,6 @@
#include "unix_private.h"
-#ifndef HAVE_NETINET_TCP_FSM_H -#define TCPS_ESTABLISHED 1 -#define TCPS_SYN_SENT 2 -#define TCPS_SYN_RECEIVED 3 -#define TCPS_FIN_WAIT_1 4 -#define TCPS_FIN_WAIT_2 5 -#define TCPS_TIME_WAIT 6 -#define TCPS_CLOSED 7 -#define TCPS_CLOSE_WAIT 8 -#define TCPS_LAST_ACK 9 -#define TCPS_LISTEN 10 -#define TCPS_CLOSING 11 -#endif - WINE_DEFAULT_DEBUG_CHANNEL(nsi);
static NTSTATUS tcp_stats_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size, @@ -215,25 +193,6 @@ static NTSTATUS tcp_stats_get_all_parameters( const void *key, UINT key_size, vo #endif }
-static inline MIB_TCP_STATE tcp_state_to_mib_state( 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; - } -} - struct ipv6_addr_scope *get_ipv6_addr_scope_table( unsigned int *size ) { struct ipv6_addr_scope *table = NULL, *new_table; @@ -515,255 +474,96 @@ unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UIN #endif }
-#ifdef __APPLE__ -static int pcblist_mib[CTL_MAXNAME]; -static size_t pcblist_mib_len = CTL_MAXNAME; - -static void init_pcblist64_mib( void ) -{ - sysctlnametomib( "net.inet.tcp.pcblist64", pcblist_mib, &pcblist_mib_len ); -} -#endif - static NTSTATUS tcp_conns_enumerate_all( UINT filter, struct nsi_tcp_conn_key *key_data, UINT key_size, void *rw, UINT rw_size, struct nsi_tcp_conn_dynamic *dynamic_data, UINT dynamic_size, struct nsi_tcp_conn_static *static_data, UINT static_size, UINT_PTR *count ) { - UINT num = 0; - NTSTATUS status = STATUS_SUCCESS; BOOL want_data = key_size || rw_size || dynamic_size || static_size; 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, pid_map_size = 0; - struct pid_map *pid_map = NULL; + unsigned int addr_scopes_size = 0; + NTSTATUS ret = STATUS_SUCCESS; + tcp_connection *connections = NULL;
-#ifdef __linux__ + if (want_data) { - FILE *fp; - char buf[512], *ptr; - int inode; - UINT laddr, raddr; - - if (!(fp = fopen( "/proc/net/tcp", "r" ))) return ERROR_NOT_SUPPORTED; - - memset( &key, 0, sizeof(key) ); - memset( &dyn, 0, sizeof(dyn) ); - memset( &stat, 0, sizeof(stat) ); - if (static_data) pid_map = get_pid_map( &pid_map_size ); - - /* skip header line */ - ptr = fgets( buf, sizeof(buf), fp ); - while ((ptr = fgets( buf, sizeof(buf), fp ))) - { - if (sscanf( ptr, "%*x: %x:%hx %x:%hx %x %*s %*s %*s %*s %*s %d", - &laddr, &key.local.Ipv4.sin_port, - &raddr, &key.remote.Ipv4.sin_port, - &dyn.state, &inode ) != 6) - continue; - dyn.state = tcp_state_to_mib_state( dyn.state ); - if (filter && filter != dyn.state ) continue; - - key.local.Ipv4.sin_family = key.remote.Ipv4.sin_family = WS_AF_INET; - key.local.Ipv4.sin_addr.WS_s_addr = laddr; - key.local.Ipv4.sin_port = htons( key.local.Ipv4.sin_port ); - key.remote.Ipv4.sin_addr.WS_s_addr = raddr; - key.remote.Ipv4.sin_port = htons( key.remote.Ipv4.sin_port ); - - if (num < *count) - { - if (key_data) *key_data++ = key; - if (dynamic_data) *dynamic_data++ = dyn; - if (static_data) - { - stat.pid = find_owning_pid( pid_map, pid_map_size, inode ); - stat.create_time = 0; /* FIXME */ - stat.mod_info = 0; /* FIXME */ - *static_data++ = stat; - } - } - num++; - } - fclose( fp ); + connections = malloc( sizeof(*connections) * (*count) ); + if (!connections) return STATUS_NO_MEMORY; + }
- if ((fp = fopen( "/proc/net/tcp6", "r" ))) + SERVER_START_REQ( get_tcp_connections ) + { + req->state_filter = filter; + wine_server_set_reply( req, connections, want_data ? (sizeof(*connections) * (*count)) : 0 ); + if (!(ret = wine_server_call( req ))) + *count = reply->count; + else if (ret == STATUS_BUFFER_TOO_SMALL) { - memset( &key, 0, sizeof(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 ))) + *count = reply->count; + if (want_data) { - UINT *local_addr = (UINT *)&key.local.Ipv6.sin6_addr; - UINT *remote_addr = (UINT *)&key.remote.Ipv6.sin6_addr; - - if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%hx %8x%8x%8x%8x:%hx %x %*s %*s %*s %*s %*s %*s %*s %d", - local_addr, local_addr + 1, local_addr + 2, local_addr + 3, &key.local.Ipv6.sin6_port, - remote_addr, remote_addr + 1, remote_addr + 2, remote_addr + 3, &key.remote.Ipv6.sin6_port, - &dyn.state, &inode ) != 12) - continue; - dyn.state = tcp_state_to_mib_state( dyn.state ); - if (filter && filter != dyn.state ) continue; - 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 = 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 ); - if (num < *count) - { - if (key_data) *key_data++ = key; - if (dynamic_data) *dynamic_data++ = dyn; - if (static_data) - { - stat.pid = find_owning_pid( pid_map, pid_map_size, inode ); - stat.create_time = 0; /* FIXME */ - stat.mod_info = 0; /* FIXME */ - *static_data++ = stat; - } - } - num++; + free( connections ); + return STATUS_BUFFER_OVERFLOW; } - fclose( fp ); + return STATUS_SUCCESS; } } -#elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_PCBLIST) && defined(HAVE_STRUCT_XINPGEN) - { - size_t len = 0; - char *buf = NULL; - struct xinpgen *xig, *orig_xig; + SERVER_END_REQ;
-#ifdef __APPLE__ - static pthread_once_t mib_init_once = PTHREAD_ONCE_INIT; - pthread_once( &mib_init_once, init_pcblist64_mib ); -#else - int pcblist_mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_PCBLIST }; - size_t pcblist_mib_len = ARRAY_SIZE(pcblist_mib); -#endif + addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
- if (sysctl( pcblist_mib, pcblist_mib_len, NULL, &len, NULL, 0 ) < 0) - { - ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" ); - status = STATUS_NOT_SUPPORTED; - goto err; - } - - buf = malloc( len ); - if (!buf) - { - status = STATUS_NO_MEMORY; - goto err; - } - - if (sysctl( pcblist_mib, pcblist_mib_len, buf, &len, NULL, 0 ) < 0) - { - ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" ); - status = STATUS_NOT_SUPPORTED; - goto err; - } - - /* 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 ); - if (static_data) pid_map = get_pid_map( &pid_map_size ); - - orig_xig = (struct xinpgen *)buf; - xig = orig_xig; + for (unsigned int i = 0; i < *count; i++) + { + tcp_connection *conn = &connections[i];
- for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); - xig->xig_len > sizeof(struct xinpgen); - xig = (struct xinpgen *)((char *)xig + xig->xig_len)) + if (key_data) { -#ifdef __APPLE__ - struct xtcpcb64 *tcp = (struct xtcpcb64 *)xig; - struct xinpcb64 *in = &tcp->xt_inpcb; - struct xsocket64 *sock = &in->xi_socket; -#elif __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 - static const struct in6_addr zero; - - /* 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 IPv4 and IPV6 addresses */ - if (!(in->inp_vflag & (INP_IPV4 | INP_IPV6))) continue; - - /* If all 0's, skip it */ - if (in->inp_vflag & INP_IPV4 && !in->inp_laddr.s_addr && !in->inp_lport && - !in->inp_faddr.s_addr && !in->inp_fport) continue; - if (in->inp_vflag & INP_IPV6 && !memcmp( &in->in6p_laddr, &zero, sizeof(zero) ) && !in->inp_lport && - !memcmp( &in->in6p_faddr, &zero, sizeof(zero) ) && !in->inp_fport) continue; - - dyn.state = tcp_state_to_mib_state( tcp->t_state ); - if (filter && filter != dyn.state ) continue; - - if (in->inp_vflag & INP_IPV4) + memset( &key, 0, sizeof(key) ); + if (conn->common.family == WS_AF_INET) { key.local.Ipv4.sin_family = key.remote.Ipv4.sin_family = WS_AF_INET; - key.local.Ipv4.sin_addr.WS_s_addr = in->inp_laddr.s_addr; - key.local.Ipv4.sin_port = in->inp_lport; - key.remote.Ipv4.sin_addr.WS_s_addr = in->inp_faddr.s_addr; - key.remote.Ipv4.sin_port = in->inp_fport; + key.local.Ipv4.sin_addr.WS_s_addr = conn->ipv4.local_addr; + key.local.Ipv4.sin_port = conn->ipv4.local_port; + key.remote.Ipv4.sin_addr.WS_s_addr = conn->ipv4.remote_addr; + key.remote.Ipv4.sin_port = conn->ipv4.remote_port; } else { 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; + memcpy( &key.local.Ipv6.sin6_addr, &conn->ipv6.local_addr, 16 ); + key.local.Ipv6.sin6_port = conn->ipv6.local_port; 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; + memcpy( &key.remote.Ipv6.sin6_addr, &conn->ipv6.remote_addr, 16 ); + key.remote.Ipv6.sin6_port = conn->ipv6.remote_port; key.remote.Ipv6.sin6_scope_id = find_ipv6_addr_scope( &key.remote.Ipv6.sin6_addr, addr_scopes, addr_scopes_size ); } + *key_data++ = key; + }
- if (num < *count) - { - if (key_data) *key_data++ = key; - if (dynamic_data) *dynamic_data++ = dyn; - if (static_data) - { - 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 */ - *static_data++ = stat; - } - } - num++; + if (dynamic_data) + { + memset( &dyn, 0, sizeof(dyn) ); + dyn.state = conn->common.state; + *dynamic_data++ = dyn; } - err: - free( buf ); - } -#else - FIXME( "not implemented\n" ); - status = STATUS_NOT_IMPLEMENTED; -#endif
- if (!want_data || num <= *count) *count = num; - else status = STATUS_BUFFER_OVERFLOW; + if (static_data) + { + memset( &stat, 0, sizeof(stat) ); + stat.pid = conn->common.owner; + stat.create_time = 0; /* FIXME */ + stat.mod_info = 0; /* FIXME */ + *static_data++ = stat; + } + }
- free( pid_map ); - free( addr_scopes ); - return status; + free( connections ); + return STATUS_SUCCESS; }
static NTSTATUS tcp_all_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size, diff --git a/server/handle.c b/server/handle.c index ef243e06e0b..c8eee98fbbc 100644 --- a/server/handle.c +++ b/server/handle.c @@ -885,6 +885,43 @@ DECL_HANDLER(get_system_handles) } }
+struct enum_process_handles_info +{ + const struct object_ops *ops; + int (*cb)(struct process*, struct object*, void*); + void *user; +}; + +static int enum_process_handles_cb( struct process *process, void *user ) +{ + struct enum_process_handles_info *info = user; + struct handle_table *table = process->handles; + struct handle_entry *entry; + unsigned int i; + + if (!table) + return 0; + + for (i = 0, entry = table->entries; i <= table->last; i++, entry++) + { + if (!entry->ptr || entry->ptr->ops != info->ops) continue; + if ((info->cb)( process, entry->ptr, info->user )) return 1; + } + + return 0; +} + +void enum_handles_of_type( const struct object_ops *ops, + int (*cb)(struct process*, struct object*, void*), void *user ) +{ + struct enum_process_handles_info info; + info.ops = ops; + info.cb = cb; + info.user = user; + + enum_processes( enum_process_handles_cb, &info ); +} + DECL_HANDLER(set_object_permanence) { const unsigned int access = req->permanent ? 0 : DELETE; diff --git a/server/handle.h b/server/handle.h index 1d02e040258..a2b06ac02b1 100644 --- a/server/handle.h +++ b/server/handle.h @@ -55,5 +55,7 @@ extern struct handle_table *copy_handle_table( struct process *process, struct p const obj_handle_t *handles, unsigned int handle_count, const obj_handle_t *std_handles ); extern unsigned int get_handle_table_count( struct process *process); +void enum_handles_of_type( const struct object_ops *ops, + int (*cb)(struct process*, struct object*, void*), void *user );
#endif /* __WINE_SERVER_HANDLE_H */ diff --git a/server/protocol.def b/server/protocol.def index 2c791cbdd46..10186946f3f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3429,6 +3429,47 @@ struct handle_info @END
+typedef union +{ + struct + { + unsigned int family; + process_id_t owner; + unsigned int state; + } common; + struct + { + unsigned int family; + process_id_t owner; + unsigned int state; + unsigned int local_addr; + unsigned int local_port; + unsigned int remote_addr; + unsigned int remote_port; + } ipv4; + struct + { + unsigned int family; + process_id_t owner; + unsigned int state; + unsigned char local_addr[16]; + unsigned int local_scope_id; + unsigned int local_port; + unsigned char remote_addr[16]; + unsigned int remote_scope_id; + unsigned int remote_port; + } ipv6; +} tcp_connection; + +/* Retrieve a list of all processes' TCP connections. */ +@REQ(get_tcp_connections) + unsigned int state_filter; /* MIB_TCP_STATE_* or 0 for no filter */ +@REPLY + unsigned int count; + VARARG(connections,tcp_connections); +@END + + /* Create a mailslot */ @REQ(create_mailslot) unsigned int access; /* wanted access rights */ diff --git a/server/sock.c b/server/sock.c index 4d159768478..fe2ef269e6d 100644 --- a/server/sock.c +++ b/server/sock.c @@ -42,6 +42,9 @@ #ifdef HAVE_NETINET_TCP_H # include <netinet/tcp.h> #endif +#ifdef HAVE_NETINET_TCP_FSM_H +#include <netinet/tcp_fsm.h> +#endif #include <poll.h> #include <sys/time.h> #include <sys/types.h> @@ -92,6 +95,7 @@ #define USE_WS_PREFIX #include "winsock2.h" #include "ws2tcpip.h" +#include "tcpmib.h" #include "wsipx.h" #include "af_irda.h" #include "wine/afd.h" @@ -108,6 +112,20 @@ #define IP_UNICAST_IF 50 #endif
+#ifndef HAVE_NETINET_TCP_FSM_H +#define TCPS_ESTABLISHED 1 +#define TCPS_SYN_SENT 2 +#define TCPS_SYN_RECEIVED 3 +#define TCPS_FIN_WAIT_1 4 +#define TCPS_FIN_WAIT_2 5 +#define TCPS_TIME_WAIT 6 +#define TCPS_CLOSED 7 +#define TCPS_CLOSE_WAIT 8 +#define TCPS_LAST_ACK 9 +#define TCPS_LISTEN 10 +#define TCPS_CLOSING 11 +#endif + static const char magic_loopback_addr[] = {127, 12, 34, 56};
union win_sockaddr @@ -4126,3 +4144,128 @@ DECL_HANDLER(socket_get_icmp_id) set_error( STATUS_NOT_FOUND ); release_object( sock ); } + +static inline MIB_TCP_STATE tcp_state_to_mib_state( 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 MIB_TCP_STATE get_tcp_socket_state( int fd ) +{ +#ifdef __APPLE__ + /* The macOS getsockopt name and struct are compatible with those on Linux + and FreeBSD, just named differently. */ + #define TCP_INFO TCP_CONNECTION_INFO + #define tcp_info tcp_connection_info +#endif + + struct tcp_info info; + socklen_t info_len = sizeof(info); + if (getsockopt( fd, IPPROTO_TCP, TCP_INFO, &info, &info_len ) == 0) + return tcp_state_to_mib_state( info.tcpi_state ); + + if (debug_level) + fprintf( stderr, "getsockopt TCP_INFO failed: %s\n", strerror( errno ) ); + + return MIB_TCP_STATE_ESTAB; +} + +struct enum_tcp_connection_info +{ + MIB_TCP_STATE state_filter; + unsigned int count; + tcp_connection *conn; +}; + +static int enum_tcp_connections( struct process *process, struct object *obj, void *user ) +{ + struct sock *sock = (struct sock *)obj; + struct enum_tcp_connection_info *info = user; + MIB_TCP_STATE socket_state; + tcp_connection *conn; + + assert( obj->ops == &sock_ops ); + + if (sock->type != WS_SOCK_STREAM || !(sock->family == WS_AF_INET || sock->family == WS_AF_INET6)) + return 0; + + socket_state = get_tcp_socket_state( get_unix_fd(sock->fd) ); + if (info->state_filter && socket_state != info->state_filter) + return 0; + + if (!info->conn) + { + info->count++; + return 0; + } + + assert( info->count ); + conn = info->conn++; + memset( conn, 0, sizeof(*conn) ); + + conn->common.family = sock->family; + conn->common.state = socket_state; + conn->common.owner = process->id; + + if (sock->family == WS_AF_INET) + { + conn->ipv4.local_addr = sock->addr.in.sin_addr.WS_s_addr; + conn->ipv4.local_port = sock->addr.in.sin_port; + if (sock->peer_addr_len) + { + conn->ipv4.remote_addr = sock->peer_addr.in.sin_addr.WS_s_addr; + conn->ipv4.remote_port = sock->peer_addr.in.sin_port; + } + } + else + { + memcpy( &conn->ipv6.local_addr, &sock->addr.in6.sin6_addr, 16 ); + conn->ipv6.local_scope_id = sock->addr.in6.sin6_scope_id; + conn->ipv6.local_port = sock->addr.in6.sin6_port; + if (sock->peer_addr_len) + { + memcpy( &conn->ipv6.remote_addr, &sock->peer_addr.in6.sin6_addr, 16 ); + conn->ipv6.remote_scope_id = sock->peer_addr.in6.sin6_scope_id; + conn->ipv6.remote_port = sock->peer_addr.in6.sin6_port; + } + } + + info->count--; + + return 0; +} + +DECL_HANDLER(get_tcp_connections) +{ + struct enum_tcp_connection_info info; + tcp_connection *conn; + data_size_t max_conns = get_reply_max_size() / sizeof(*conn); + + info.state_filter = req->state_filter; + info.conn = NULL; + info.count = 0; + enum_handles_of_type( &sock_ops, enum_tcp_connections, &info ); + reply->count = info.count; + + if (max_conns < info.count) + set_error( STATUS_BUFFER_TOO_SMALL ); + else if ((conn = set_reply_data_size( info.count * sizeof(*conn) ))) + { + info.conn = conn; + enum_handles_of_type( &sock_ops, enum_tcp_connections, &info ); + } +} diff --git a/server/trace.c b/server/trace.c index 96dc5781d4c..cf3768f5a65 100644 --- a/server/trace.c +++ b/server/trace.c @@ -24,6 +24,17 @@ #include <stdarg.h> #include <stdio.h> #include <sys/types.h> +#include <sys/socket.h> + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif
#ifdef HAVE_SYS_UIO_H #include <sys/uio.h> @@ -42,6 +53,8 @@ #include "ddk/ntddser.h" #define USE_WS_PREFIX #include "winsock2.h" +#include "ws2tcpip.h" +#include "tcpmib.h" #include "file.h" #include "request.h" #include "security.h" @@ -1380,6 +1393,60 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) fputc( '}', stderr ); }
+static void dump_varargs_tcp_connections( const char *prefix, data_size_t size ) +{ + static const char * const state_names[] = { + NULL, + "CLOSED", + "LISTEN", + "SYN_SENT", + "SYN_RCVD", + "ESTAB", + "FIN_WAIT1", + "FIN_WAIT2", + "CLOSE_WAIT", + "CLOSING", + "LAST_ACK", + "TIME_WAIT", + "DELETE_TCB" + }; + const tcp_connection *conn; + + fprintf( stderr, "%s{", prefix ); + while (size >= sizeof(*conn)) + { + conn = cur_data; + + if (conn->common.family == WS_AF_INET) + { + char local_addr_str[INET_ADDRSTRLEN] = { 0 }; + char remote_addr_str[INET_ADDRSTRLEN] = { 0 }; + inet_ntop( AF_INET, (struct in_addr *)&conn->ipv4.local_addr, local_addr_str, INET_ADDRSTRLEN ); + inet_ntop( AF_INET, (struct in_addr *)&conn->ipv4.remote_addr, remote_addr_str, INET_ADDRSTRLEN ); + fprintf( stderr, "{family=AF_INET,owner=%04x,state=%s,local=%s:%d,remote=%s:%d}", + conn->ipv4.owner, state_names[conn->ipv4.state], + local_addr_str, conn->ipv4.local_port, + remote_addr_str, conn->ipv4.remote_port ); + } + else + { + char local_addr_str[INET6_ADDRSTRLEN]; + char remote_addr_str[INET6_ADDRSTRLEN]; + inet_ntop( AF_INET6, (struct in6_addr *)&conn->ipv6.local_addr, local_addr_str, INET6_ADDRSTRLEN ); + inet_ntop( AF_INET6, (struct in6_addr *)&conn->ipv6.remote_addr, remote_addr_str, INET6_ADDRSTRLEN ); + fprintf( stderr, "{family=AF_INET6,owner=%04x,state=%s,local=[%s%%%d]:%d,remote=[%s%%%d]:%d}", + conn->ipv6.owner, state_names[conn->ipv6.state], + local_addr_str, conn->ipv6.local_scope_id, conn->ipv6.local_port, + remote_addr_str, conn->ipv6.remote_scope_id, conn->ipv6.remote_port ); + } + + size -= sizeof(*conn); + remove_data( sizeof(*conn) ); + if (size) fputc( ',', stderr ); + } + fputc( '}', stderr ); +} + static void dump_varargs_directory_entries( const char *prefix, data_size_t size ) { fprintf( stderr, "%s{", prefix ); diff --git a/tools/make_requests b/tools/make_requests index 36254faec40..65ddcd0ffb8 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -64,6 +64,7 @@ my %formats = "property_data_t" => [ 16, 8 ], "select_op_t" => [ 264, 8 ], "startup_info_t" => [ 96, 4 ], + "tcp_connection" => [ 60, 4 ], "user_apc_t" => [ 40, 8 ], "struct filesystem_event" => [ 12, 4 ], "struct handle_info" => [ 20, 4 ],